Refactoring of VolumeSettings to extend VolumeConfig
[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 from novaclient.exceptions import BadRequest
25
26 from snaps import file_utils
27 from snaps.config.volume import VolumeConfig
28 from snaps.config.router import RouterConfig
29 from snaps.config.keypair import KeypairConfig
30 from snaps.openstack import create_network, create_router
31 from snaps.config.flavor import FlavorConfig
32 from snaps.openstack.create_flavor import OpenStackFlavor
33 from snaps.config.image import ImageConfig
34 from snaps.openstack.create_image import OpenStackImage
35 from snaps.openstack.create_instance import (
36     VmInstanceSettings, OpenStackVmInstance, FloatingIpSettings,
37     VmInstanceSettingsError, FloatingIpSettingsError)
38 from snaps.openstack.create_keypairs import OpenStackKeypair
39 from snaps.openstack.create_network import (
40     OpenStackNetwork, PortSettings, NetworkSettings, SubnetSettings)
41 from snaps.openstack.create_router import OpenStackRouter
42 from snaps.openstack.create_security_group import (
43     SecurityGroupSettings, OpenStackSecurityGroup, SecurityGroupRuleSettings,
44     Direction, Protocol)
45 from snaps.openstack.create_volume import OpenStackVolume
46 from snaps.openstack.tests import openstack_tests, validation_utils
47 from snaps.openstack.tests.os_source_file_test import (
48     OSIntegrationTestCase, OSComponentTestCase)
49 from snaps.openstack.utils import nova_utils
50
51 __author__ = 'spisarski'
52
53 VM_BOOT_TIMEOUT = 600
54
55 logger = logging.getLogger('create_instance_tests')
56
57
58 class VmInstanceSettingsUnitTests(unittest.TestCase):
59     """
60     Tests the construction of the VmInstanceSettings class
61     """
62
63     def test_no_params(self):
64         with self.assertRaises(VmInstanceSettingsError):
65             VmInstanceSettings()
66
67     def test_empty_config(self):
68         with self.assertRaises(VmInstanceSettingsError):
69             VmInstanceSettings(config=dict())
70
71     def test_name_only(self):
72         with self.assertRaises(VmInstanceSettingsError):
73             VmInstanceSettings(name='foo')
74
75     def test_config_with_name_only(self):
76         with self.assertRaises(VmInstanceSettingsError):
77             VmInstanceSettings(config={'name': 'foo'})
78
79     def test_name_flavor_only(self):
80         with self.assertRaises(VmInstanceSettingsError):
81             VmInstanceSettings(name='foo', flavor='bar')
82
83     def test_config_with_name_flavor_only(self):
84         with self.assertRaises(VmInstanceSettingsError):
85             VmInstanceSettings(config={'name': 'foo', 'flavor': 'bar'})
86
87     def test_name_flavor_port_only(self):
88         port_settings = PortSettings(name='foo-port', network_name='bar-net')
89         settings = VmInstanceSettings(name='foo', flavor='bar',
90                                       port_settings=[port_settings])
91         self.assertEqual('foo', settings.name)
92         self.assertEqual('bar', settings.flavor)
93         self.assertEqual(1, len(settings.port_settings))
94         self.assertEqual('foo-port', settings.port_settings[0].name)
95         self.assertEqual('bar-net', settings.port_settings[0].network_name)
96         self.assertEqual(0, len(settings.security_group_names))
97         self.assertEqual(0, len(settings.floating_ip_settings))
98         self.assertIsNone(settings.sudo_user)
99         self.assertEqual(900, settings.vm_boot_timeout)
100         self.assertEqual(300, settings.vm_delete_timeout)
101         self.assertEqual(180, settings.ssh_connect_timeout)
102         self.assertIsNone(settings.availability_zone)
103         self.assertIsNone(settings.volume_names)
104
105     def test_config_with_name_flavor_port_only(self):
106         port_settings = PortSettings(name='foo-port', network_name='bar-net')
107         settings = VmInstanceSettings(
108             **{'name': 'foo', 'flavor': 'bar', 'ports': [port_settings]})
109         self.assertEqual('foo', settings.name)
110         self.assertEqual('bar', settings.flavor)
111         self.assertEqual(1, len(settings.port_settings))
112         self.assertEqual('foo-port', settings.port_settings[0].name)
113         self.assertEqual('bar-net', settings.port_settings[0].network_name)
114         self.assertEqual(0, len(settings.security_group_names))
115         self.assertEqual(0, len(settings.floating_ip_settings))
116         self.assertIsNone(settings.sudo_user)
117         self.assertEqual(900, settings.vm_boot_timeout)
118         self.assertEqual(300, settings.vm_delete_timeout)
119         self.assertEqual(180, settings.ssh_connect_timeout)
120         self.assertIsNone(settings.availability_zone)
121         self.assertIsNone(settings.volume_names)
122
123     def test_all(self):
124         port_settings = PortSettings(name='foo-port', network_name='bar-net')
125         fip_settings = FloatingIpSettings(name='foo-fip', port_name='bar-port',
126                                           router_name='foo-bar-router')
127
128         settings = VmInstanceSettings(
129             name='foo', flavor='bar', port_settings=[port_settings],
130             security_group_names=['sec_grp_1'],
131             floating_ip_settings=[fip_settings], sudo_user='joe',
132             vm_boot_timeout=999, vm_delete_timeout=333,
133             ssh_connect_timeout=111, availability_zone='server name',
134             volume_names=['vol1'])
135         self.assertEqual('foo', settings.name)
136         self.assertEqual('bar', settings.flavor)
137         self.assertEqual(1, len(settings.port_settings))
138         self.assertEqual('foo-port', settings.port_settings[0].name)
139         self.assertEqual('bar-net', settings.port_settings[0].network_name)
140         self.assertEqual(1, len(settings.security_group_names))
141         self.assertEqual('sec_grp_1', settings.security_group_names[0])
142         self.assertEqual(1, len(settings.floating_ip_settings))
143         self.assertEqual('foo-fip', settings.floating_ip_settings[0].name)
144         self.assertEqual('bar-port',
145                          settings.floating_ip_settings[0].port_name)
146         self.assertEqual('foo-bar-router',
147                          settings.floating_ip_settings[0].router_name)
148         self.assertEqual('joe', settings.sudo_user)
149         self.assertEqual(999, settings.vm_boot_timeout)
150         self.assertEqual(333, settings.vm_delete_timeout)
151         self.assertEqual(111, settings.ssh_connect_timeout)
152         self.assertEqual('server name', settings.availability_zone)
153         self.assertEqual('vol1', settings.volume_names[0])
154
155     def test_config_all(self):
156         port_settings = PortSettings(name='foo-port', network_name='bar-net')
157         fip_settings = FloatingIpSettings(name='foo-fip', port_name='bar-port',
158                                           router_name='foo-bar-router')
159
160         settings = VmInstanceSettings(
161             **{'name': 'foo', 'flavor': 'bar', 'ports': [port_settings],
162                'security_group_names': ['sec_grp_1'],
163                'floating_ips': [fip_settings], 'sudo_user': 'joe',
164                'vm_boot_timeout': 999, 'vm_delete_timeout': 333,
165                'ssh_connect_timeout': 111, 'availability_zone': 'server name',
166                'volume_names': ['vol2']})
167         self.assertEqual('foo', settings.name)
168         self.assertEqual('bar', settings.flavor)
169         self.assertEqual(1, len(settings.port_settings))
170         self.assertEqual('foo-port', settings.port_settings[0].name)
171         self.assertEqual('bar-net', settings.port_settings[0].network_name)
172         self.assertEqual(1, len(settings.security_group_names))
173         self.assertEqual(1, len(settings.floating_ip_settings))
174         self.assertEqual('foo-fip', settings.floating_ip_settings[0].name)
175         self.assertEqual('bar-port',
176                          settings.floating_ip_settings[0].port_name)
177         self.assertEqual('foo-bar-router',
178                          settings.floating_ip_settings[0].router_name)
179         self.assertEqual('joe', settings.sudo_user)
180         self.assertEqual(999, settings.vm_boot_timeout)
181         self.assertEqual(333, settings.vm_delete_timeout)
182         self.assertEqual(111, settings.ssh_connect_timeout)
183         self.assertEqual('server name', settings.availability_zone)
184         self.assertEqual('vol2', settings.volume_names[0])
185
186
187 class FloatingIpSettingsUnitTests(unittest.TestCase):
188     """
189     Tests the construction of the FloatingIpSettings class
190     """
191
192     def test_no_params(self):
193         with self.assertRaises(FloatingIpSettingsError):
194             FloatingIpSettings()
195
196     def test_empty_config(self):
197         with self.assertRaises(FloatingIpSettingsError):
198             FloatingIpSettings(**dict())
199
200     def test_name_only(self):
201         with self.assertRaises(FloatingIpSettingsError):
202             FloatingIpSettings(name='foo')
203
204     def test_config_with_name_only(self):
205         with self.assertRaises(FloatingIpSettingsError):
206             FloatingIpSettings(**{'name': 'foo'})
207
208     def test_name_port_only(self):
209         with self.assertRaises(FloatingIpSettingsError):
210             FloatingIpSettings(name='foo', port_name='bar')
211
212     def test_config_with_name_port_only(self):
213         with self.assertRaises(FloatingIpSettingsError):
214             FloatingIpSettings(**{'name': 'foo', 'port_name': 'bar'})
215
216     def test_name_router_only(self):
217         with self.assertRaises(FloatingIpSettingsError):
218             FloatingIpSettings(name='foo', router_name='bar')
219
220     def test_config_with_name_router_only(self):
221         with self.assertRaises(FloatingIpSettingsError):
222             FloatingIpSettings(**{'name': 'foo', 'router_name': 'bar'})
223
224     def test_name_port_router_name_only(self):
225         settings = FloatingIpSettings(name='foo', port_name='foo-port',
226                                       router_name='bar-router')
227         self.assertEqual('foo', settings.name)
228         self.assertEqual('foo-port', settings.port_name)
229         self.assertIsNone(settings.port_id)
230         self.assertEqual('bar-router', settings.router_name)
231         self.assertIsNone(settings.subnet_name)
232         self.assertTrue(settings.provisioning)
233
234     def test_name_port_router_id_only(self):
235         settings = FloatingIpSettings(name='foo', port_id='foo-port',
236                                       router_name='bar-router')
237         self.assertEqual('foo', settings.name)
238         self.assertEqual('foo-port', settings.port_id)
239         self.assertIsNone(settings.port_name)
240         self.assertEqual('bar-router', settings.router_name)
241         self.assertIsNone(settings.subnet_name)
242         self.assertTrue(settings.provisioning)
243
244     def test_config_with_name_port_router_only(self):
245         settings = FloatingIpSettings(
246             **{'name': 'foo', 'port_name': 'foo-port',
247                'router_name': 'bar-router'})
248         self.assertEqual('foo', settings.name)
249         self.assertEqual('foo-port', settings.port_name)
250         self.assertIsNone(settings.port_id)
251         self.assertEqual('bar-router', settings.router_name)
252         self.assertIsNone(settings.subnet_name)
253         self.assertTrue(settings.provisioning)
254
255     def test_all(self):
256         settings = FloatingIpSettings(name='foo', port_name='foo-port',
257                                       router_name='bar-router',
258                                       subnet_name='bar-subnet',
259                                       provisioning=False)
260         self.assertEqual('foo', settings.name)
261         self.assertEqual('foo-port', settings.port_name)
262         self.assertIsNone(settings.port_id)
263         self.assertEqual('bar-router', settings.router_name)
264         self.assertEqual('bar-subnet', settings.subnet_name)
265         self.assertFalse(settings.provisioning)
266
267     def test_config_all(self):
268         settings = FloatingIpSettings(
269             **{'name': 'foo', 'port_name': 'foo-port',
270                'router_name': 'bar-router', 'subnet_name': 'bar-subnet',
271                'provisioning': False})
272         self.assertEqual('foo', settings.name)
273         self.assertEqual('foo-port', settings.port_name)
274         self.assertIsNone(settings.port_id)
275         self.assertEqual('bar-router', settings.router_name)
276         self.assertEqual('bar-subnet', settings.subnet_name)
277         self.assertFalse(settings.provisioning)
278
279
280 class SimpleHealthCheck(OSIntegrationTestCase):
281     """
282     Test for the CreateInstance class with a single NIC/Port with Floating IPs
283     """
284
285     def setUp(self):
286         """
287         Instantiates the CreateImage object that is responsible for downloading
288         and creating an OS image file
289         within OpenStack
290         """
291         super(self.__class__, self).__start__()
292
293         self.nova = nova_utils.nova_client(self.os_creds)
294         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
295         self.vm_inst_name = guid + '-inst'
296         self.port_1_name = guid + 'port-1'
297
298         # Initialize for tearDown()
299         self.image_creator = None
300         self.network_creator = None
301         self.flavor_creator = None
302         self.inst_creator = None
303
304         self.priv_net_config = openstack_tests.get_priv_net_config(
305             net_name=guid + '-priv-net', subnet_name=guid + '-priv-subnet')
306         self.port_settings = PortSettings(
307             name=self.port_1_name,
308             network_name=self.priv_net_config.network_settings.name)
309
310         # Create Image
311         # Set the default image settings, then set any custom parameters sent
312         # from the app
313         os_image_settings = openstack_tests.cirros_image_settings(
314             name=guid + '-image', image_metadata=self.image_metadata)
315
316         try:
317             self.image_creator = OpenStackImage(self.os_creds,
318                                                 os_image_settings)
319             self.image_creator.create()
320
321             # Create Network
322             self.network_creator = OpenStackNetwork(
323                 self.os_creds, self.priv_net_config.network_settings)
324             self.network_creator.create()
325
326             # Create Flavor
327             self.flavor_creator = OpenStackFlavor(
328                 self.admin_os_creds,
329                 FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10,
330                              vcpus=1, metadata=self.flavor_metadata))
331             self.flavor_creator.create()
332         except Exception as e:
333             self.tearDown()
334             raise e
335
336     def tearDown(self):
337         """
338         Cleans the created object
339         """
340         if self.inst_creator:
341             try:
342                 self.inst_creator.clean()
343             except Exception as e:
344                 logger.error(
345                     'Unexpected exception cleaning VM instance with message'
346                     ' - %s', e)
347
348         if self.network_creator:
349             try:
350                 self.network_creator.clean()
351             except Exception as e:
352                 logger.error(
353                     'Unexpected exception cleaning network with message - %s',
354                     e)
355
356         if self.flavor_creator:
357             try:
358                 self.flavor_creator.clean()
359             except Exception as e:
360                 logger.error(
361                     'Unexpected exception cleaning flavor with message - %s',
362                     e)
363
364         if self.image_creator and not self.image_creator.image_settings.exists:
365             try:
366                 self.image_creator.clean()
367             except Exception as e:
368                 logger.error(
369                     'Unexpected exception cleaning image with message - %s',
370                     e)
371
372         super(self.__class__, self).__clean__()
373
374     def test_check_vm_ip_dhcp(self):
375         """
376         Tests the creation of an OpenStack instance with a single port and
377         ensures that it's assigned IP address is the actual.
378         """
379         instance_settings = VmInstanceSettings(
380             name=self.vm_inst_name,
381             flavor=self.flavor_creator.flavor_settings.name,
382             port_settings=[self.port_settings])
383
384         self.inst_creator = OpenStackVmInstance(
385             self.os_creds, instance_settings,
386             self.image_creator.image_settings)
387         self.inst_creator.create()
388
389         ip = self.inst_creator.get_port_ip(self.port_settings.name)
390         self.assertIsNotNone(ip)
391
392         self.assertTrue(self.inst_creator.vm_active(block=True))
393
394         self.assertTrue(check_dhcp_lease(self.inst_creator, ip))
395
396
397 class CreateInstanceSimpleTests(OSIntegrationTestCase):
398     """
399     Simple instance creation tests without any other objects
400     """
401
402     def setUp(self):
403         """
404         Instantiates the CreateImage object that is responsible for downloading
405         and creating an OS image file
406         within OpenStack
407         """
408         super(self.__class__, self).__start__()
409
410         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
411         self.vm_inst_name = guid + '-inst'
412         self.nova = nova_utils.nova_client(self.os_creds)
413         os_image_settings = openstack_tests.cirros_image_settings(
414             name=guid + '-image', image_metadata=self.image_metadata)
415
416         net_config = openstack_tests.get_priv_net_config(
417             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
418             router_name=guid + '-pub-router', external_net=self.ext_net_name)
419
420         # Initialize for tearDown()
421         self.image_creator = None
422         self.flavor_creator = None
423
424         self.network_creator = None
425         self.inst_creator = None
426
427         try:
428             # Create Image
429             self.image_creator = OpenStackImage(self.os_creds,
430                                                 os_image_settings)
431             self.image_creator.create()
432
433             # Create Flavor
434             self.flavor_creator = OpenStackFlavor(
435                 self.admin_os_creds,
436                 FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10,
437                              vcpus=2, metadata=self.flavor_metadata))
438             self.flavor_creator.create()
439
440             # Create Network
441             self.network_creator = OpenStackNetwork(
442                 self.os_creds, net_config.network_settings)
443             self.network_creator.create()
444
445             self.port_settings = PortSettings(
446                 name=guid + '-port',
447                 network_name=net_config.network_settings.name)
448
449         except Exception as e:
450             self.tearDown()
451             raise e
452
453     def tearDown(self):
454         """
455         Cleans the created object
456         """
457         if self.inst_creator:
458             try:
459                 self.inst_creator.clean()
460             except Exception as e:
461                 logger.error(
462                     'Unexpected exception cleaning VM instance with message '
463                     '- %s', e)
464
465         if self.flavor_creator:
466             try:
467                 self.flavor_creator.clean()
468             except Exception as e:
469                 logger.error(
470                     'Unexpected exception cleaning flavor with message - %s',
471                     e)
472
473         if self.network_creator:
474             try:
475                 self.network_creator.clean()
476             except Exception as e:
477                 logger.error(
478                     'Unexpected exception cleaning network with message - %s',
479                     e)
480
481         if self.image_creator and not self.image_creator.image_settings.exists:
482             try:
483                 self.image_creator.clean()
484             except Exception as e:
485                 logger.error(
486                     'Unexpected exception cleaning image with message - %s', e)
487
488         super(self.__class__, self).__clean__()
489
490     def test_create_delete_instance(self):
491         """
492         Tests the creation of an OpenStack instance with a single port with a
493         static IP without a Floating IP.
494         """
495         instance_settings = VmInstanceSettings(
496             name=self.vm_inst_name,
497             flavor=self.flavor_creator.flavor_settings.name,
498             port_settings=[self.port_settings])
499
500         self.inst_creator = OpenStackVmInstance(
501             self.os_creds, instance_settings,
502             self.image_creator.image_settings)
503
504         vm_inst = self.inst_creator.create()
505         self.assertIsNotNone(nova_utils.get_server(
506             self.nova, vm_inst_settings=instance_settings))
507
508         # Delete instance
509         nova_utils.delete_vm_instance(self.nova, vm_inst)
510
511         self.assertTrue(self.inst_creator.vm_deleted(block=True))
512         self.assertIsNone(nova_utils.get_server(
513             self.nova, vm_inst_settings=instance_settings))
514
515         # Exception should not be thrown
516         self.inst_creator.clean()
517
518
519 class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
520     """
521     Test for the CreateInstance class with a single NIC/Port with Floating IPs
522     """
523
524     def setUp(self):
525         """
526         Instantiates the CreateImage object that is responsible for downloading
527         and creating an OS image file within OpenStack
528         """
529         super(self.__class__, self).__start__()
530
531         self.nova = nova_utils.nova_client(self.os_creds)
532         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
533         self.keypair_priv_filepath = 'tmp/' + guid
534         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
535         self.keypair_name = guid + '-kp'
536         self.vm_inst_name = guid + '-inst'
537         self.port_1_name = guid + 'port-1'
538         self.port_2_name = guid + 'port-2'
539         self.floating_ip_name = guid + 'fip1'
540
541         # Initialize for tearDown()
542         self.image_creator = None
543         self.network_creator = None
544         self.router_creator = None
545         self.flavor_creator = None
546         self.keypair_creator = None
547         self.sec_grp_creator = None
548         self.inst_creators = list()
549
550         self.pub_net_config = openstack_tests.get_pub_net_config(
551             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
552             router_name=guid + '-pub-router', external_net=self.ext_net_name)
553         os_image_settings = openstack_tests.cirros_image_settings(
554             name=guid + '-image', image_metadata=self.image_metadata)
555         try:
556             # Create Image
557             self.image_creator = OpenStackImage(self.os_creds,
558                                                 os_image_settings)
559             self.image_creator.create()
560
561             # Create Network
562             self.network_creator = OpenStackNetwork(
563                 self.os_creds, self.pub_net_config.network_settings)
564             self.network_creator.create()
565
566             # Create Router
567             self.router_creator = OpenStackRouter(
568                 self.os_creds, self.pub_net_config.router_settings)
569             self.router_creator.create()
570
571             # Create Flavor
572             self.flavor_creator = OpenStackFlavor(
573                 self.admin_os_creds,
574                 FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10,
575                              vcpus=2, metadata=self.flavor_metadata))
576             self.flavor_creator.create()
577
578             self.keypair_creator = OpenStackKeypair(
579                 self.os_creds, KeypairConfig(
580                     name=self.keypair_name,
581                     public_filepath=self.keypair_pub_filepath,
582                     private_filepath=self.keypair_priv_filepath))
583             self.keypair_creator.create()
584
585             sec_grp_name = guid + '-sec-grp'
586             rule1 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
587                                               direction=Direction.ingress,
588                                               protocol=Protocol.icmp)
589             rule2 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
590                                               direction=Direction.ingress,
591                                               protocol=Protocol.tcp,
592                                               port_range_min=22,
593                                               port_range_max=22)
594             self.sec_grp_creator = OpenStackSecurityGroup(
595                 self.os_creds,
596                 SecurityGroupSettings(name=sec_grp_name,
597                                       rule_settings=[rule1, rule2]))
598             self.sec_grp_creator.create()
599         except Exception as e:
600             self.tearDown()
601             raise e
602
603     def tearDown(self):
604         """
605         Cleans the created object
606         """
607         for inst_creator in self.inst_creators:
608             try:
609                 inst_creator.clean()
610             except Exception as e:
611                 logger.error(
612                     'Unexpected exception cleaning VM instance with message '
613                     '- %s', e)
614
615         if self.keypair_creator:
616             try:
617                 self.keypair_creator.clean()
618             except Exception as e:
619                 logger.error(
620                     'Unexpected exception cleaning keypair with message - %s',
621                     e)
622
623         if self.flavor_creator:
624             try:
625                 self.flavor_creator.clean()
626             except Exception as e:
627                 logger.error(
628                     'Unexpected exception cleaning flavor with message - %s',
629                     e)
630
631         if self.sec_grp_creator:
632             try:
633                 self.sec_grp_creator.clean()
634             except Exception as e:
635                 logger.error(
636                     'Unexpected exception cleaning security group with message'
637                     ' - %s', e)
638
639         if self.router_creator:
640             try:
641                 self.router_creator.clean()
642             except Exception as e:
643                 logger.error(
644                     'Unexpected exception cleaning router with message - %s',
645                     e)
646
647         if self.network_creator:
648             try:
649                 self.network_creator.clean()
650             except Exception as e:
651                 logger.error(
652                     'Unexpected exception cleaning network with message - %s',
653                     e)
654
655         if self.image_creator and not self.image_creator.image_settings.exists:
656             try:
657                 self.image_creator.clean()
658             except Exception as e:
659                 logger.error(
660                     'Unexpected exception cleaning image with message - %s', e)
661
662         super(self.__class__, self).__clean__()
663
664     def test_single_port_static(self):
665         """
666         Tests the creation of an OpenStack instance with a single port with a
667         static IP without a Floating IP.
668         """
669         ip_1 = '10.55.1.100'
670         sub_settings = self.pub_net_config.network_settings.subnet_settings
671         port_settings = PortSettings(
672             name=self.port_1_name,
673             network_name=self.pub_net_config.network_settings.name,
674             ip_addrs=[
675                 {'subnet_name': sub_settings[0].name, 'ip': ip_1}])
676
677         instance_settings = VmInstanceSettings(
678             name=self.vm_inst_name,
679             flavor=self.flavor_creator.flavor_settings.name,
680             port_settings=[port_settings],
681             floating_ip_settings=[FloatingIpSettings(
682                 name=self.floating_ip_name, port_name=self.port_1_name,
683                 router_name=self.pub_net_config.router_settings.name)])
684
685         inst_creator = OpenStackVmInstance(
686             self.os_creds, instance_settings,
687             self.image_creator.image_settings,
688             keypair_settings=self.keypair_creator.keypair_settings)
689         self.inst_creators.append(inst_creator)
690         vm_inst = inst_creator.create(block=True)
691
692         self.assertEqual(ip_1, inst_creator.get_port_ip(self.port_1_name))
693         self.assertTrue(inst_creator.vm_active(block=True))
694         self.assertEqual(vm_inst.id, inst_creator.get_vm_inst().id)
695
696     def test_ssh_client_fip_before_active(self):
697         """
698         Tests the ability to access a VM via SSH and a floating IP when it has
699         been assigned prior to being active.
700         """
701         port_settings = PortSettings(
702             name=self.port_1_name,
703             network_name=self.pub_net_config.network_settings.name)
704
705         instance_settings = VmInstanceSettings(
706             name=self.vm_inst_name,
707             flavor=self.flavor_creator.flavor_settings.name,
708             port_settings=[port_settings],
709             security_group_names=[self.sec_grp_creator.sec_grp_settings.name],
710             floating_ip_settings=[FloatingIpSettings(
711                 name=self.floating_ip_name, port_name=self.port_1_name,
712                 router_name=self.pub_net_config.router_settings.name)])
713
714         inst_creator = OpenStackVmInstance(
715             self.os_creds, instance_settings,
716             self.image_creator.image_settings,
717             keypair_settings=self.keypair_creator.keypair_settings)
718         self.inst_creators.append(inst_creator)
719         vm_inst = inst_creator.create()
720         self.assertIsNotNone(vm_inst)
721
722         self.assertTrue(inst_creator.vm_active(block=True))
723
724         ip = inst_creator.get_port_ip(port_settings.name)
725         self.assertTrue(check_dhcp_lease(inst_creator, ip))
726
727         self.assertEqual(vm_inst.id, inst_creator.get_vm_inst().id)
728
729         self.assertTrue(validate_ssh_client(inst_creator))
730
731     def test_ssh_client_fip_after_active(self):
732         """
733         Tests the ability to access a VM via SSH and a floating IP when it has
734         been assigned prior to being active.
735         """
736         port_settings = PortSettings(
737             name=self.port_1_name,
738             network_name=self.pub_net_config.network_settings.name)
739
740         instance_settings = VmInstanceSettings(
741             name=self.vm_inst_name,
742             flavor=self.flavor_creator.flavor_settings.name,
743             port_settings=[port_settings],
744             security_group_names=[self.sec_grp_creator.sec_grp_settings.name],
745             floating_ip_settings=[FloatingIpSettings(
746                 name=self.floating_ip_name, port_name=self.port_1_name,
747                 router_name=self.pub_net_config.router_settings.name)])
748
749         inst_creator = OpenStackVmInstance(
750             self.os_creds, instance_settings,
751             self.image_creator.image_settings,
752             keypair_settings=self.keypair_creator.keypair_settings)
753         self.inst_creators.append(inst_creator)
754
755         # block=True will force the create() method to block until the
756         vm_inst = inst_creator.create(block=True)
757         self.assertIsNotNone(vm_inst)
758
759         self.assertTrue(inst_creator.vm_active(block=True))
760
761         ip = inst_creator.get_port_ip(port_settings.name)
762         self.assertTrue(check_dhcp_lease(inst_creator, ip))
763
764         self.assertEqual(vm_inst.id, inst_creator.get_vm_inst().id)
765
766         self.assertTrue(validate_ssh_client(inst_creator))
767
768     def test_ssh_client_fip_second_creator(self):
769         """
770         Tests the ability to access a VM via SSH and a floating IP via a
771         creator that is identical to the original creator.
772         """
773         port_settings = PortSettings(
774             name=self.port_1_name,
775             network_name=self.pub_net_config.network_settings.name)
776
777         instance_settings = VmInstanceSettings(
778             name=self.vm_inst_name,
779             flavor=self.flavor_creator.flavor_settings.name,
780             port_settings=[port_settings],
781             security_group_names=[self.sec_grp_creator.sec_grp_settings.name],
782             floating_ip_settings=[FloatingIpSettings(
783                 name=self.floating_ip_name, port_name=self.port_1_name,
784                 router_name=self.pub_net_config.router_settings.name)])
785
786         inst_creator = OpenStackVmInstance(
787             self.os_creds, instance_settings,
788             self.image_creator.image_settings,
789             keypair_settings=self.keypair_creator.keypair_settings)
790         self.inst_creators.append(inst_creator)
791
792         # block=True will force the create() method to block until the
793         vm_inst = inst_creator.create(block=True)
794         self.assertIsNotNone(vm_inst)
795
796         self.assertTrue(inst_creator.vm_active(block=True))
797
798         ip = inst_creator.get_port_ip(port_settings.name)
799         self.assertTrue(check_dhcp_lease(inst_creator, ip))
800
801         self.assertEqual(vm_inst.id, inst_creator.get_vm_inst().id)
802
803         self.assertTrue(validate_ssh_client(inst_creator))
804
805         inst_creator2 = OpenStackVmInstance(
806             self.os_creds, instance_settings,
807             self.image_creator.image_settings,
808             keypair_settings=self.keypair_creator.keypair_settings)
809         inst_creator2.create()
810         self.assertTrue(validate_ssh_client(inst_creator2))
811
812
813 class CreateInstanceIPv6NetworkTests(OSIntegrationTestCase):
814     """
815     Test for the CreateInstance class with a single NIC/Port with Floating IPs
816     """
817
818     def setUp(self):
819         """
820         Instantiates the CreateImage object that is responsible for downloading
821         and creating an OS image file within OpenStack
822         """
823         super(self.__class__, self).__start__()
824
825         self.nova = nova_utils.nova_client(self.os_creds)
826         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
827         self.keypair_priv_filepath = 'tmp/' + self.guid
828         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
829         self.keypair_name = self.guid + '-kp'
830         self.vm_inst_name = self.guid + '-inst'
831         self.port1_name = self.guid + 'port1'
832         self.port2_name = self.guid + 'port2'
833
834         # Initialize for tearDown()
835         self.image_creator = None
836         self.network_creator = None
837         self.router_creator = None
838         self.flavor_creator = None
839         self.keypair_creator = None
840         self.sec_grp_creator = None
841         self.inst_creator = None
842
843         os_image_settings = openstack_tests.cirros_image_settings(
844             name=self.guid + '-image', image_metadata=self.image_metadata)
845         try:
846             self.image_creator = OpenStackImage(
847                 self.os_creds, os_image_settings)
848             self.image_creator.create()
849
850             self.flavor_creator = OpenStackFlavor(
851                 self.admin_os_creds,
852                 FlavorConfig(
853                     name=self.guid + '-flavor-name', ram=256, disk=10, vcpus=2,
854                     metadata=self.flavor_metadata))
855             self.flavor_creator.create()
856
857             self.keypair_creator = OpenStackKeypair(
858                 self.os_creds, KeypairConfig(
859                     name=self.keypair_name,
860                     public_filepath=self.keypair_pub_filepath,
861                     private_filepath=self.keypair_priv_filepath))
862             self.keypair_creator.create()
863
864             sec_grp_name = self.guid + '-sec-grp'
865             rule1 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
866                                               direction=Direction.ingress,
867                                               protocol=Protocol.icmp)
868             rule2 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
869                                               direction=Direction.ingress,
870                                               protocol=Protocol.tcp,
871                                               port_range_min=22,
872                                               port_range_max=22)
873             self.sec_grp_creator = OpenStackSecurityGroup(
874                 self.os_creds,
875                 SecurityGroupSettings(name=sec_grp_name,
876                                       rule_settings=[rule1, rule2]))
877             self.sec_grp_creator.create()
878         except Exception as e:
879             self.tearDown()
880             raise e
881
882     def tearDown(self):
883         """
884         Cleans the created object
885         """
886         if self.inst_creator:
887             try:
888                 self.inst_creator.clean()
889             except Exception as e:
890                 logger.error(
891                     'Unexpected exception cleaning VM instance with message '
892                     '- %s', e)
893
894         if self.keypair_creator:
895             try:
896                 self.keypair_creator.clean()
897             except Exception as e:
898                 logger.error(
899                     'Unexpected exception cleaning keypair with message - %s',
900                     e)
901
902         if self.flavor_creator:
903             try:
904                 self.flavor_creator.clean()
905             except Exception as e:
906                 logger.error(
907                     'Unexpected exception cleaning flavor with message - %s',
908                     e)
909
910         if self.sec_grp_creator:
911             try:
912                 self.sec_grp_creator.clean()
913             except Exception as e:
914                 logger.error(
915                     'Unexpected exception cleaning security group with message'
916                     ' - %s', e)
917
918         if self.router_creator:
919             try:
920                 self.router_creator.clean()
921             except Exception as e:
922                 logger.error(
923                     'Unexpected exception cleaning router with message - %s',
924                     e)
925
926         if self.network_creator:
927             try:
928                 self.network_creator.clean()
929             except Exception as e:
930                 logger.error(
931                     'Unexpected exception cleaning network with message - %s',
932                     e)
933
934         if self.image_creator and not self.image_creator.image_settings.exists:
935             try:
936                 self.image_creator.clean()
937             except Exception as e:
938                 logger.error(
939                     'Unexpected exception cleaning image with message - %s', e)
940
941         super(self.__class__, self).__clean__()
942
943     def test_v4fip_v6overlay(self):
944         """
945         Tests the ability to assign an IPv4 floating IP to an IPv6 overlay
946         network when the external network does not have an IPv6 subnet.
947         """
948         subnet_settings = SubnetSettings(
949             name=self.guid + '-subnet', cidr='1:1:0:0:0:0:0:0/64',
950             ip_version=6)
951         network_settings = NetworkSettings(
952             name=self.guid + '-net', subnet_settings=[subnet_settings])
953         router_settings = RouterConfig(
954             name=self.guid + '-router', external_gateway=self.ext_net_name,
955             internal_subnets=[subnet_settings.name])
956
957         # Create Network
958         self.network_creator = OpenStackNetwork(
959             self.os_creds, network_settings)
960         self.network_creator.create()
961
962         # Create Router
963         self.router_creator = OpenStackRouter(
964             self.os_creds, router_settings)
965         self.router_creator.create()
966
967         port_settings = PortSettings(
968             name=self.port1_name, network_name=network_settings.name)
969
970         instance_settings = VmInstanceSettings(
971             name=self.vm_inst_name,
972             flavor=self.flavor_creator.flavor_settings.name,
973             port_settings=[port_settings],
974             security_group_names=[self.sec_grp_creator.sec_grp_settings.name],
975             floating_ip_settings=[FloatingIpSettings(
976                 name='fip1', port_name=self.port1_name,
977                 router_name=router_settings.name)])
978
979         self.inst_creator = OpenStackVmInstance(
980             self.os_creds, instance_settings,
981             self.image_creator.image_settings,
982             keypair_settings=self.keypair_creator.keypair_settings)
983
984         with self.assertRaises(BadRequest):
985             self.inst_creator.create(block=True)
986
987     def test_fip_v4and6_overlay(self):
988         """
989         Tests the ability to assign an IPv4 floating IP to an IPv6 overlay
990         network when the external network does not have an IPv6 subnet.
991         """
992         subnet4_settings = SubnetSettings(
993             name=self.guid + '-subnet4', cidr='10.0.1.0/24',
994             ip_version=4)
995         subnet6_settings = SubnetSettings(
996             name=self.guid + '-subnet6', cidr='1:1:0:0:0:0:0:0/64',
997             ip_version=6)
998         network_settings = NetworkSettings(
999             name=self.guid + '-net',
1000             subnet_settings=[subnet4_settings, subnet6_settings])
1001         router_settings = RouterConfig(
1002             name=self.guid + '-router', external_gateway=self.ext_net_name,
1003             internal_subnets=[subnet4_settings.name])
1004
1005         # Create Network
1006         self.network_creator = OpenStackNetwork(
1007             self.os_creds, network_settings)
1008         self.network_creator.create()
1009
1010         # Create Router
1011         self.router_creator = OpenStackRouter(
1012             self.os_creds, router_settings)
1013         self.router_creator.create()
1014
1015         port_settings = PortSettings(
1016             name=self.port1_name, network_name=network_settings.name)
1017
1018         instance_settings = VmInstanceSettings(
1019             name=self.vm_inst_name,
1020             flavor=self.flavor_creator.flavor_settings.name,
1021             port_settings=[port_settings],
1022             security_group_names=[self.sec_grp_creator.sec_grp_settings.name],
1023             floating_ip_settings=[FloatingIpSettings(
1024                 name='fip1', port_name=self.port1_name,
1025                 router_name=router_settings.name)])
1026
1027         self.inst_creator = OpenStackVmInstance(
1028             self.os_creds, instance_settings,
1029             self.image_creator.image_settings,
1030             keypair_settings=self.keypair_creator.keypair_settings)
1031
1032         self.inst_creator.create(block=True)
1033         ssh_client = self.inst_creator.ssh_client()
1034         self.assertIsNotNone(ssh_client)
1035
1036
1037 class CreateInstancePortManipulationTests(OSIntegrationTestCase):
1038     """
1039     Test for the CreateInstance class with a single NIC/Port where mac and IP
1040     values are manually set
1041     """
1042
1043     def setUp(self):
1044         """
1045         Instantiates the CreateImage object that is responsible for downloading
1046         and creating an OS image file within OpenStack
1047         """
1048         super(self.__class__, self).__start__()
1049
1050         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1051         self.vm_inst_name = guid + '-inst'
1052         self.port_1_name = guid + 'port-1'
1053         self.port_2_name = guid + 'port-2'
1054         self.floating_ip_name = guid + 'fip1'
1055
1056         # Initialize for tearDown()
1057         self.image_creator = None
1058         self.network_creator = None
1059         self.flavor_creator = None
1060         self.inst_creator = None
1061
1062         self.net_config = openstack_tests.get_priv_net_config(
1063             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
1064             router_name=guid + '-pub-router', external_net=self.ext_net_name)
1065         os_image_settings = openstack_tests.cirros_image_settings(
1066             name=guid + '-image', image_metadata=self.image_metadata)
1067
1068         try:
1069             # Create Image
1070             self.image_creator = OpenStackImage(self.os_creds,
1071                                                 os_image_settings)
1072             self.image_creator.create()
1073
1074             # Create Network
1075             self.network_creator = OpenStackNetwork(
1076                 self.os_creds, self.net_config.network_settings)
1077             self.network_creator.create()
1078
1079             # Create Flavor
1080             self.flavor_creator = OpenStackFlavor(
1081                 self.admin_os_creds,
1082                 FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10,
1083                              vcpus=2, metadata=self.flavor_metadata))
1084             self.flavor_creator.create()
1085         except Exception as e:
1086             self.tearDown()
1087             raise e
1088
1089     def tearDown(self):
1090         """
1091         Cleans the created object
1092         """
1093         if self.inst_creator:
1094             try:
1095                 self.inst_creator.clean()
1096             except Exception as e:
1097                 logger.error(
1098                     'Unexpected exception cleaning VM instance with message '
1099                     '- %s', e)
1100
1101         if self.flavor_creator:
1102             try:
1103                 self.flavor_creator.clean()
1104             except Exception as e:
1105                 logger.error(
1106                     'Unexpected exception cleaning flavor with message - %s',
1107                     e)
1108
1109         if self.network_creator:
1110             try:
1111                 self.network_creator.clean()
1112             except Exception as e:
1113                 logger.error(
1114                     'Unexpected exception cleaning network with message - %s',
1115                     e)
1116
1117         if self.image_creator and not self.image_creator.image_settings.exists:
1118             try:
1119                 self.image_creator.clean()
1120             except Exception as e:
1121                 logger.error(
1122                     'Unexpected exception cleaning image with message - %s', e)
1123
1124         super(self.__class__, self).__clean__()
1125
1126     def test_set_custom_valid_ip_one_subnet(self):
1127         """
1128         Tests the creation of an OpenStack instance with a single port with a
1129         static IP on a network with one subnet.
1130         """
1131         ip = '10.55.0.101'
1132         sub_settings = self.net_config.network_settings.subnet_settings
1133         port_settings = PortSettings(
1134             name=self.port_1_name,
1135             network_name=self.net_config.network_settings.name,
1136             ip_addrs=[{'subnet_name': sub_settings[0].name, 'ip': ip}])
1137
1138         instance_settings = VmInstanceSettings(
1139             name=self.vm_inst_name,
1140             flavor=self.flavor_creator.flavor_settings.name,
1141             port_settings=[port_settings])
1142
1143         self.inst_creator = OpenStackVmInstance(
1144             self.os_creds, instance_settings,
1145             self.image_creator.image_settings)
1146         self.inst_creator.create(block=True)
1147
1148         self.assertEqual(ip, self.inst_creator.get_port_ip(
1149             self.port_1_name,
1150             subnet_name=self.net_config.network_settings.subnet_settings[
1151                 0].name))
1152
1153     def test_set_custom_invalid_ip_one_subnet(self):
1154         """
1155         Tests the creation of an OpenStack instance with a single port with a
1156         static IP on a network with one subnet.
1157         """
1158         ip = '10.66.0.101'
1159         sub_settings = self.net_config.network_settings.subnet_settings
1160         port_settings = PortSettings(
1161             name=self.port_1_name,
1162             network_name=self.net_config.network_settings.name,
1163             ip_addrs=[{'subnet_name': sub_settings[0].name, 'ip': ip}])
1164
1165         instance_settings = VmInstanceSettings(
1166             name=self.vm_inst_name,
1167             flavor=self.flavor_creator.flavor_settings.name,
1168             port_settings=[port_settings])
1169
1170         self.inst_creator = OpenStackVmInstance(
1171             self.os_creds, instance_settings,
1172             self.image_creator.image_settings)
1173
1174         with self.assertRaises(InvalidIpForSubnetClient):
1175             self.inst_creator.create()
1176
1177     def test_set_custom_valid_mac(self):
1178         """
1179         Tests the creation of an OpenStack instance with a single port where
1180         the MAC address is assigned.
1181         """
1182         mac_addr = '0a:1b:2c:3d:4e:5f'
1183         port_settings = PortSettings(
1184             name=self.port_1_name,
1185             network_name=self.net_config.network_settings.name,
1186             mac_address=mac_addr)
1187
1188         instance_settings = VmInstanceSettings(
1189             name=self.vm_inst_name,
1190             flavor=self.flavor_creator.flavor_settings.name,
1191             port_settings=[port_settings])
1192
1193         self.inst_creator = OpenStackVmInstance(
1194             self.os_creds, instance_settings,
1195             self.image_creator.image_settings)
1196         self.inst_creator.create(block=True)
1197
1198         self.assertEqual(mac_addr,
1199                          self.inst_creator.get_port_mac(self.port_1_name))
1200
1201     def test_set_custom_invalid_mac(self):
1202         """
1203         Tests the creation of an OpenStack instance with a single port where an
1204         invalid MAC address value is being
1205         assigned. This should raise an Exception
1206         """
1207         port_settings = PortSettings(
1208             name=self.port_1_name,
1209             network_name=self.net_config.network_settings.name,
1210             mac_address='foo')
1211
1212         instance_settings = VmInstanceSettings(
1213             name=self.vm_inst_name,
1214             flavor=self.flavor_creator.flavor_settings.name,
1215             port_settings=[port_settings])
1216
1217         self.inst_creator = OpenStackVmInstance(
1218             self.os_creds, instance_settings,
1219             self.image_creator.image_settings)
1220
1221         with self.assertRaises(Exception):
1222             self.inst_creator.create()
1223
1224     def test_set_custom_mac_and_ip(self):
1225         """
1226         Tests the creation of an OpenStack instance with a single port where
1227         the IP and MAC address is assigned.
1228         """
1229         ip = '10.55.0.101'
1230         mac_addr = '0a:1b:2c:3d:4e:5f'
1231         sub_settings = self.net_config.network_settings.subnet_settings
1232         port_settings = PortSettings(
1233             name=self.port_1_name,
1234             network_name=self.net_config.network_settings.name,
1235             mac_address=mac_addr,
1236             ip_addrs=[{'subnet_name': sub_settings[0].name, 'ip': ip}])
1237
1238         instance_settings = VmInstanceSettings(
1239             name=self.vm_inst_name,
1240             flavor=self.flavor_creator.flavor_settings.name,
1241             port_settings=[port_settings])
1242
1243         self.inst_creator = OpenStackVmInstance(
1244             self.os_creds, instance_settings,
1245             self.image_creator.image_settings)
1246         self.inst_creator.create(block=True)
1247
1248         self.assertEqual(ip, self.inst_creator.get_port_ip(
1249             self.port_1_name,
1250             subnet_name=self.net_config.network_settings.subnet_settings[
1251                 0].name))
1252         self.assertEqual(mac_addr,
1253                          self.inst_creator.get_port_mac(self.port_1_name))
1254
1255     def test_set_allowed_address_pairs(self):
1256         """
1257         Tests the creation of an OpenStack instance with a single port where
1258         max_allowed_address_pair is set.
1259         """
1260         ip = '10.55.0.101'
1261         mac_addr = '0a:1b:2c:3d:4e:5f'
1262         pair = {'ip_address': ip, 'mac_address': mac_addr}
1263         port_settings = PortSettings(
1264             name=self.port_1_name,
1265             network_name=self.net_config.network_settings.name,
1266             allowed_address_pairs=[pair])
1267
1268         instance_settings = VmInstanceSettings(
1269             name=self.vm_inst_name,
1270             flavor=self.flavor_creator.flavor_settings.name,
1271             port_settings=[port_settings])
1272
1273         self.inst_creator = OpenStackVmInstance(
1274             self.os_creds, instance_settings,
1275             self.image_creator.image_settings)
1276         self.inst_creator.create(block=True)
1277
1278         port = self.inst_creator.get_port_by_name(port_settings.name)
1279         self.assertIsNotNone(port)
1280         self.assertIsNotNone(port.allowed_address_pairs)
1281         self.assertEqual(1, len(port.allowed_address_pairs))
1282         validation_utils.objects_equivalent(pair,
1283                                             port.allowed_address_pairs[0])
1284
1285     def test_set_allowed_address_pairs_bad_mac(self):
1286         """
1287         Tests the creation of an OpenStack instance with a single port where
1288         max_allowed_address_pair is set with an invalid MAC address.
1289         """
1290         ip = '10.55.0.101'
1291         mac_addr = 'foo'
1292         pair = {'ip_address': ip, 'mac_address': mac_addr}
1293         pairs = set()
1294         pairs.add((ip, mac_addr))
1295         port_settings = PortSettings(
1296             name=self.port_1_name,
1297             network_name=self.net_config.network_settings.name,
1298             allowed_address_pairs=[pair])
1299
1300         instance_settings = VmInstanceSettings(
1301             name=self.vm_inst_name,
1302             flavor=self.flavor_creator.flavor_settings.name,
1303             port_settings=[port_settings])
1304
1305         self.inst_creator = OpenStackVmInstance(
1306             self.os_creds, instance_settings,
1307             self.image_creator.image_settings)
1308         with self.assertRaises(Exception):
1309             self.inst_creator.create()
1310
1311     def test_set_allowed_address_pairs_bad_ip(self):
1312         """
1313         Tests the creation of an OpenStack instance with a single port where
1314         max_allowed_address_pair is set with an invalid MAC address.
1315         """
1316         ip = 'foo'
1317         mac_addr = '0a:1b:2c:3d:4e:5f'
1318         pair = {'ip_address': ip, 'mac_address': mac_addr}
1319         pairs = set()
1320         pairs.add((ip, mac_addr))
1321         port_settings = PortSettings(
1322             name=self.port_1_name,
1323             network_name=self.net_config.network_settings.name,
1324             allowed_address_pairs=[pair])
1325
1326         instance_settings = VmInstanceSettings(
1327             name=self.vm_inst_name,
1328             flavor=self.flavor_creator.flavor_settings.name,
1329             port_settings=[port_settings])
1330
1331         self.inst_creator = OpenStackVmInstance(
1332             self.os_creds, instance_settings,
1333             self.image_creator.image_settings)
1334         with self.assertRaises(Exception):
1335             self.inst_creator.create()
1336
1337
1338 class CreateInstanceOnComputeHost(OSIntegrationTestCase):
1339     """
1340     Test for the CreateInstance where one VM is deployed to each compute node
1341     """
1342
1343     def setUp(self):
1344         """
1345         Instantiates the CreateImage object that is responsible for downloading
1346         and creating an OS image file within OpenStack
1347         """
1348         super(self.__class__, self).__start__()
1349
1350         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1351         self.vm_inst_name = guid + '-inst'
1352         self.port_base_name = guid + 'port'
1353
1354         # Initialize for tearDown()
1355         self.image_creator = None
1356         self.flavor_creator = None
1357         self.network_creator = None
1358         self.inst_creators = list()
1359
1360         self.priv_net_config = openstack_tests.get_priv_net_config(
1361             net_name=guid + '-priv-net', subnet_name=guid + '-priv-subnet')
1362
1363         os_image_settings = openstack_tests.cirros_image_settings(
1364             name=guid + '-image', image_metadata=self.image_metadata)
1365
1366         try:
1367             # Create Network
1368             self.network_creator = OpenStackNetwork(
1369                 self.admin_os_creds, self.priv_net_config.network_settings)
1370             self.network_creator.create()
1371
1372             # Create Flavor
1373             self.flavor_creator = OpenStackFlavor(
1374                 self.admin_os_creds,
1375                 FlavorConfig(name=guid + '-flavor-name', ram=512, disk=1,
1376                              vcpus=1, metadata=self.flavor_metadata))
1377             self.flavor_creator.create()
1378
1379             # Create Image
1380             self.image_creator = OpenStackImage(self.os_creds,
1381                                                 os_image_settings)
1382             self.image_creator.create()
1383
1384         except Exception as e:
1385             self.tearDown()
1386             raise e
1387
1388     def tearDown(self):
1389         """
1390         Cleans the created object
1391         """
1392         for inst_creator in self.inst_creators:
1393             try:
1394                 inst_creator.clean()
1395             except Exception as e:
1396                 logger.error(
1397                     'Unexpected exception cleaning VM instance with message '
1398                     '- %s', e)
1399
1400         if self.flavor_creator:
1401             try:
1402                 self.flavor_creator.clean()
1403             except Exception as e:
1404                 logger.error(
1405                     'Unexpected exception cleaning flavor with message - %s',
1406                     e)
1407
1408         if self.network_creator:
1409             try:
1410                 self.network_creator.clean()
1411             except Exception as e:
1412                 logger.error(
1413                     'Unexpected exception cleaning network with message - %s',
1414                     e)
1415
1416         if self.image_creator and not self.image_creator.image_settings.exists:
1417             try:
1418                 self.image_creator.clean()
1419             except Exception as e:
1420                 logger.error(
1421                     'Unexpected exception cleaning image with message - %s', e)
1422
1423         super(self.__class__, self).__clean__()
1424
1425     def test_deploy_vm_to_each_compute_node(self):
1426         """
1427         Tests the creation of OpenStack VM instances to each compute node.
1428         """
1429         from snaps.openstack.utils import nova_utils
1430         nova = nova_utils.nova_client(self.admin_os_creds)
1431         zone_hosts = nova_utils.get_availability_zone_hosts(nova)
1432
1433         # Create Instance on each server/zone
1434         ctr = 0
1435         for zone in zone_hosts:
1436             inst_name = self.vm_inst_name + '-' + zone
1437             ctr += 1
1438             port_settings = PortSettings(
1439                 name=self.port_base_name + '-' + str(ctr),
1440                 network_name=self.priv_net_config.network_settings.name)
1441
1442             instance_settings = VmInstanceSettings(
1443                 name=inst_name,
1444                 flavor=self.flavor_creator.flavor_settings.name,
1445                 availability_zone=zone,
1446                 port_settings=[port_settings])
1447             inst_creator = OpenStackVmInstance(
1448                 self.admin_os_creds, instance_settings,
1449                 self.image_creator.image_settings)
1450             self.inst_creators.append(inst_creator)
1451             inst_creator.create()
1452
1453         # Validate instances to ensure they've been deployed to the correct
1454         # server
1455         index = 0
1456         for zone in zone_hosts:
1457             creator = self.inst_creators[index]
1458             self.assertTrue(creator.vm_active(block=True))
1459             info = creator.get_vm_info()
1460             deployed_zone = info['OS-EXT-AZ:availability_zone']
1461             deployed_host = info['OS-EXT-SRV-ATTR:host']
1462             self.assertEqual(zone, deployed_zone + ':' + deployed_host)
1463             index += 1
1464
1465
1466 class CreateInstancePubPrivNetTests(OSIntegrationTestCase):
1467     """
1468     Test for the CreateInstance class with two NIC/Ports, eth0 with floating IP
1469     and eth1 w/o.
1470     These tests require a Centos image
1471     """
1472
1473     def setUp(self):
1474         """
1475         Instantiates the CreateImage object that is responsible for downloading
1476         and creating an OS image file within OpenStack
1477         """
1478         super(self.__class__, self).__start__()
1479
1480         self.nova = nova_utils.nova_client(self.os_creds)
1481
1482         # Initialize for tearDown()
1483         self.image_creator = None
1484         self.network_creators = list()
1485         self.router_creators = list()
1486         self.flavor_creator = None
1487         self.keypair_creator = None
1488         self.sec_grp_creator = None
1489         self.inst_creator = None
1490
1491         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1492         self.keypair_priv_filepath = 'tmp/' + self.guid
1493         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
1494         self.keypair_name = self.guid + '-kp'
1495         self.vm_inst_name = self.guid + '-inst'
1496         self.port_1_name = self.guid + '-port-1'
1497         self.port_2_name = self.guid + '-port-2'
1498         self.floating_ip_name = self.guid + 'fip1'
1499         self.priv_net_config = openstack_tests.get_priv_net_config(
1500             net_name=self.guid + '-priv-net',
1501             subnet_name=self.guid + '-priv-subnet',
1502             router_name=self.guid + '-priv-router',
1503             external_net=self.ext_net_name)
1504         self.pub_net_config = openstack_tests.get_pub_net_config(
1505             net_name=self.guid + '-pub-net',
1506             subnet_name=self.guid + '-pub-subnet',
1507             router_name=self.guid + '-pub-router',
1508             external_net=self.ext_net_name)
1509
1510         image_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
1511         os_image_settings = openstack_tests.centos_image_settings(
1512             name=image_name, image_metadata=self.image_metadata)
1513
1514         try:
1515             # Create Image
1516             self.image_creator = OpenStackImage(self.os_creds,
1517                                                 os_image_settings)
1518             self.image_creator.create()
1519
1520             # First network is public
1521             self.network_creators.append(OpenStackNetwork(
1522                 self.os_creds, self.pub_net_config.network_settings))
1523             # Second network is private
1524             self.network_creators.append(OpenStackNetwork(
1525                 self.os_creds, self.priv_net_config.network_settings))
1526             for network_creator in self.network_creators:
1527                 network_creator.create()
1528
1529             self.router_creators.append(OpenStackRouter(
1530                 self.os_creds, self.pub_net_config.router_settings))
1531             self.router_creators.append(OpenStackRouter(
1532                 self.os_creds, self.priv_net_config.router_settings))
1533
1534             # Create Routers
1535             for router_creator in self.router_creators:
1536                 router_creator.create()
1537
1538             # Create Flavor
1539             self.flavor_creator = OpenStackFlavor(
1540                 self.admin_os_creds,
1541                 FlavorConfig(name=self.guid + '-flavor-name', ram=512,
1542                              disk=10, vcpus=2,
1543                              metadata=self.flavor_metadata))
1544             self.flavor_creator.create()
1545
1546             # Create Keypair
1547             self.keypair_creator = OpenStackKeypair(
1548                 self.os_creds, KeypairConfig(
1549                     name=self.keypair_name,
1550                     public_filepath=self.keypair_pub_filepath,
1551                     private_filepath=self.keypair_priv_filepath))
1552             self.keypair_creator.create()
1553
1554             sec_grp_name = self.guid + '-sec-grp'
1555             rule1 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
1556                                               direction=Direction.ingress,
1557                                               protocol=Protocol.icmp)
1558             rule2 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
1559                                               direction=Direction.ingress,
1560                                               protocol=Protocol.tcp,
1561                                               port_range_min=22,
1562                                               port_range_max=22)
1563             self.sec_grp_creator = OpenStackSecurityGroup(
1564                 self.os_creds,
1565                 SecurityGroupSettings(name=sec_grp_name,
1566                                       rule_settings=[rule1, rule2]))
1567             self.sec_grp_creator.create()
1568         except:
1569             self.tearDown()
1570             raise
1571
1572     def tearDown(self):
1573         """
1574         Cleans the created objects
1575         """
1576         if self.inst_creator:
1577             try:
1578                 self.inst_creator.clean()
1579             except Exception as e:
1580                 logger.error(
1581                     'Unexpected exception cleaning VM instance with message '
1582                     '- %s', e)
1583
1584         if self.keypair_creator:
1585             try:
1586                 self.keypair_creator.clean()
1587             except Exception as e:
1588                 logger.error(
1589                     'Unexpected exception cleaning keypair with message - %s',
1590                     e)
1591
1592         if self.flavor_creator:
1593             try:
1594                 self.flavor_creator.clean()
1595             except Exception as e:
1596                 logger.error(
1597                     'Unexpected exception cleaning flavor with message - %s',
1598                     e)
1599
1600         for router_creator in self.router_creators:
1601             try:
1602                 router_creator.clean()
1603             except Exception as e:
1604                 logger.error(
1605                     'Unexpected exception cleaning router with message - %s',
1606                     e)
1607
1608         for network_creator in self.network_creators:
1609             try:
1610                 network_creator.clean()
1611             except Exception as e:
1612                 logger.error(
1613                     'Unexpected exception cleaning network with message - %s',
1614                     e)
1615
1616         if self.sec_grp_creator:
1617             try:
1618                 self.sec_grp_creator.clean()
1619             except Exception as e:
1620                 logger.error(
1621                     'Unexpected exception cleaning security group with message'
1622                     ' - %s', e)
1623
1624         if self.image_creator and not self.image_creator.image_settings.exists:
1625             try:
1626                 self.image_creator.clean()
1627             except Exception as e:
1628                 logger.error(
1629                     'Unexpected exception cleaning image with message - %s', e)
1630
1631         super(self.__class__, self).__clean__()
1632
1633     def test_dual_ports_dhcp(self):
1634         """
1635         Tests the creation of an OpenStack instance with a dual ports/NICs with
1636         a DHCP assigned IP.
1637         NOTE: This test and any others that call ansible will most likely fail
1638         unless you do one of two things:
1639         1. Have a ~/.ansible.cfg (or alternate means) to
1640            set host_key_checking = False
1641         2. Set the following environment variable in your executing shell:
1642            ANSIBLE_HOST_KEY_CHECKING=False
1643         Should this not be performed, the creation of the host ssh key will
1644         cause your ansible calls to fail.
1645         """
1646         # Create ports/NICs for instance
1647         ports_settings = []
1648         ctr = 1
1649         for network_creator in self.network_creators:
1650             ports_settings.append(PortSettings(
1651                 name=self.guid + '-port-' + str(ctr),
1652                 network_name=network_creator.network_settings.name))
1653             ctr += 1
1654
1655         # Create instance
1656         instance_settings = VmInstanceSettings(
1657             name=self.vm_inst_name,
1658             flavor=self.flavor_creator.flavor_settings.name,
1659             port_settings=ports_settings,
1660             security_group_names=[self.sec_grp_creator.sec_grp_settings.name],
1661             floating_ip_settings=[FloatingIpSettings(
1662                 name=self.floating_ip_name, port_name=self.port_1_name,
1663                 router_name=self.pub_net_config.router_settings.name)])
1664
1665         self.inst_creator = OpenStackVmInstance(
1666             self.os_creds, instance_settings,
1667             self.image_creator.image_settings,
1668             keypair_settings=self.keypair_creator.keypair_settings)
1669
1670         vm_inst = self.inst_creator.create(block=True)
1671
1672         self.assertEqual(vm_inst.id, self.inst_creator.get_vm_inst().id)
1673
1674         # Effectively blocks until VM has been properly activated
1675         self.assertTrue(self.inst_creator.vm_active(block=True))
1676
1677         ip = self.inst_creator.get_port_ip(ports_settings[0].name)
1678         self.assertTrue(check_dhcp_lease(self.inst_creator, ip))
1679
1680         # Effectively blocks until VM's ssh port has been opened
1681         self.assertTrue(self.inst_creator.vm_ssh_active(block=True))
1682
1683         self.assertEqual(0, self.inst_creator.config_nics())
1684
1685
1686 class InstanceSecurityGroupTests(OSIntegrationTestCase):
1687     """
1688     Tests that include, add, and remove security groups from VM instances
1689     """
1690
1691     def setUp(self):
1692         """
1693         Instantiates the CreateImage object that is responsible for downloading
1694         and creating an OS image file within OpenStack
1695         """
1696         super(self.__class__, self).__start__()
1697
1698         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1699         self.vm_inst_name = self.guid + '-inst'
1700         self.nova = nova_utils.nova_client(self.os_creds)
1701         os_image_settings = openstack_tests.cirros_image_settings(
1702             name=self.guid + '-image', image_metadata=self.image_metadata)
1703
1704         self.vm_inst_name = self.guid + '-inst'
1705         self.port_1_name = self.guid + 'port-1'
1706         self.port_2_name = self.guid + 'port-2'
1707         self.floating_ip_name = self.guid + 'fip1'
1708
1709         net_config = openstack_tests.get_priv_net_config(
1710             net_name=self.guid + '-pub-net',
1711             subnet_name=self.guid + '-pub-subnet',
1712             router_name=self.guid + '-pub-router',
1713             external_net=self.ext_net_name)
1714
1715         # Initialize for tearDown()
1716         self.image_creator = None
1717         self.flavor_creator = None
1718         self.network_creator = None
1719         self.router_creator = None
1720         self.inst_creator = None
1721         self.sec_grp_creators = list()
1722
1723         try:
1724             # Create Image
1725             self.image_creator = OpenStackImage(self.os_creds,
1726                                                 os_image_settings)
1727             self.image_creator.create()
1728
1729             # Create Network
1730             self.network_creator = OpenStackNetwork(
1731                 self.os_creds, net_config.network_settings)
1732             self.network_creator.create()
1733
1734             # Create Flavor
1735             self.flavor_creator = OpenStackFlavor(
1736                 self.admin_os_creds,
1737                 FlavorConfig(name=self.guid + '-flavor-name', ram=256,
1738                              disk=10, vcpus=2,
1739                              metadata=self.flavor_metadata))
1740             self.flavor_creator.create()
1741
1742             self.port_settings = PortSettings(
1743                 name=self.guid + '-port',
1744                 network_name=net_config.network_settings.name)
1745         except Exception as e:
1746             self.tearDown()
1747             raise e
1748
1749     def tearDown(self):
1750         """
1751         Cleans the created object
1752         """
1753         if self.inst_creator:
1754             try:
1755                 self.inst_creator.clean()
1756             except Exception as e:
1757                 logger.error(
1758                     'Unexpected exception cleaning VM instance with message -'
1759                     ' %s', e)
1760
1761         for sec_grp_creator in self.sec_grp_creators:
1762             try:
1763                 sec_grp_creator.clean()
1764             except Exception as e:
1765                 logger.error(
1766                     'Unexpected exception cleaning security group with message'
1767                     ' - %s', e)
1768
1769         if self.flavor_creator:
1770             try:
1771                 self.flavor_creator.clean()
1772             except Exception as e:
1773                 logger.error(
1774                     'Unexpected exception cleaning flavor with message - %s',
1775                     e)
1776
1777         if self.network_creator:
1778             try:
1779                 self.network_creator.clean()
1780             except Exception as e:
1781                 logger.error(
1782                     'Unexpected exception cleaning network with message - %s',
1783                     e)
1784
1785         if self.image_creator and not self.image_creator.image_settings.exists:
1786             try:
1787                 self.image_creator.clean()
1788             except Exception as e:
1789                 logger.error(
1790                     'Unexpected exception cleaning image with message - %s', e)
1791
1792         super(self.__class__, self).__clean__()
1793
1794     def test_add_security_group(self):
1795         """
1796         Tests the addition of a security group created after the instance.
1797         """
1798         # Create instance
1799         instance_settings = VmInstanceSettings(
1800             name=self.vm_inst_name,
1801             flavor=self.flavor_creator.flavor_settings.name,
1802             port_settings=[self.port_settings])
1803         self.inst_creator = OpenStackVmInstance(
1804             self.os_creds, instance_settings,
1805             self.image_creator.image_settings)
1806         vm_inst = self.inst_creator.create(block=True)
1807         self.assertIsNotNone(vm_inst)
1808
1809         # Create security group object to add to instance
1810         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name',
1811                                                  description='hello group')
1812         sec_grp_creator = OpenStackSecurityGroup(self.os_creds,
1813                                                  sec_grp_settings)
1814         sec_grp = sec_grp_creator.create()
1815         self.sec_grp_creators.append(sec_grp_creator)
1816
1817         # Check that group has not been added
1818         self.assertFalse(inst_has_sec_grp(
1819             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1820
1821         # Add security group to instance after activated
1822         self.inst_creator.add_security_group(sec_grp)
1823
1824         # Validate that security group has been added
1825         self.assertTrue(inst_has_sec_grp(
1826             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1827
1828     def test_add_invalid_security_group(self):
1829         """
1830         Tests the addition of a security group that no longer exists.
1831         """
1832         # Create instance
1833         instance_settings = VmInstanceSettings(
1834             name=self.vm_inst_name,
1835             flavor=self.flavor_creator.flavor_settings.name,
1836             port_settings=[self.port_settings])
1837         self.inst_creator = OpenStackVmInstance(
1838             self.os_creds, instance_settings,
1839             self.image_creator.image_settings)
1840         vm_inst = self.inst_creator.create(block=True)
1841         self.assertIsNotNone(vm_inst)
1842
1843         # Create security group object to add to instance
1844         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name',
1845                                                  description='hello group')
1846         sec_grp_creator = OpenStackSecurityGroup(self.os_creds,
1847                                                  sec_grp_settings)
1848         sec_grp = sec_grp_creator.create()
1849         sec_grp_creator.clean()
1850         self.sec_grp_creators.append(sec_grp_creator)
1851
1852         # Check that group has not been added
1853         self.assertFalse(inst_has_sec_grp(
1854             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1855
1856         # Add security group to instance after activated
1857         self.assertFalse(self.inst_creator.add_security_group(sec_grp))
1858
1859         # Validate that security group has been added
1860         self.assertFalse(inst_has_sec_grp(
1861             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1862
1863     def test_remove_security_group(self):
1864         """
1865         Tests the removal of a security group created before and added to the
1866         instance.
1867         """
1868         # Create security group object to add to instance
1869         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name',
1870                                                  description='hello group')
1871         sec_grp_creator = OpenStackSecurityGroup(self.os_creds,
1872                                                  sec_grp_settings)
1873         sec_grp = sec_grp_creator.create()
1874         self.sec_grp_creators.append(sec_grp_creator)
1875
1876         # Create instance
1877         instance_settings = VmInstanceSettings(
1878             name=self.vm_inst_name,
1879             flavor=self.flavor_creator.flavor_settings.name,
1880             security_group_names=[sec_grp_settings.name],
1881             port_settings=[self.port_settings])
1882         self.inst_creator = OpenStackVmInstance(
1883             self.os_creds, instance_settings,
1884             self.image_creator.image_settings)
1885         vm_inst = self.inst_creator.create(block=True)
1886         self.assertIsNotNone(vm_inst)
1887
1888         # Check that group has been added
1889         self.assertTrue(inst_has_sec_grp(
1890             self.nova, vm_inst, sec_grp_settings.name))
1891
1892         # Add security group to instance after activated
1893         self.assertTrue(self.inst_creator.remove_security_group(sec_grp))
1894
1895         # Validate that security group has been added
1896         self.assertFalse(inst_has_sec_grp(
1897             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1898
1899     def test_remove_security_group_never_added(self):
1900         """
1901         Tests the removal of a security group that was never added in the first
1902         place.
1903         """
1904         # Create security group object to add to instance
1905         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name',
1906                                                  description='hello group')
1907         sec_grp_creator = OpenStackSecurityGroup(self.os_creds,
1908                                                  sec_grp_settings)
1909         sec_grp = sec_grp_creator.create()
1910         self.sec_grp_creators.append(sec_grp_creator)
1911
1912         # Create instance
1913         instance_settings = VmInstanceSettings(
1914             name=self.vm_inst_name,
1915             flavor=self.flavor_creator.flavor_settings.name,
1916             port_settings=[self.port_settings])
1917         self.inst_creator = OpenStackVmInstance(
1918             self.os_creds, instance_settings,
1919             self.image_creator.image_settings)
1920         vm_inst = self.inst_creator.create(block=True)
1921         self.assertIsNotNone(vm_inst)
1922
1923         # Check that group has been added
1924         self.assertFalse(inst_has_sec_grp(
1925             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1926
1927         # Add security group to instance after activated
1928         self.assertFalse(self.inst_creator.remove_security_group(sec_grp))
1929
1930         # Validate that security group has been added
1931         self.assertFalse(inst_has_sec_grp(
1932             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1933
1934     def test_add_same_security_group(self):
1935         """
1936         Tests the addition of a security group created before add added to the
1937         instance.
1938         """
1939         # Create security group object to add to instance
1940         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name',
1941                                                  description='hello group')
1942         sec_grp_creator = OpenStackSecurityGroup(self.os_creds,
1943                                                  sec_grp_settings)
1944         sec_grp = sec_grp_creator.create()
1945         self.sec_grp_creators.append(sec_grp_creator)
1946
1947         # Create instance
1948         instance_settings = VmInstanceSettings(
1949             name=self.vm_inst_name,
1950             flavor=self.flavor_creator.flavor_settings.name,
1951             security_group_names=[sec_grp_settings.name],
1952             port_settings=[self.port_settings])
1953         self.inst_creator = OpenStackVmInstance(
1954             self.os_creds, instance_settings,
1955             self.image_creator.image_settings)
1956         vm_inst = self.inst_creator.create(block=True)
1957         self.assertIsNotNone(vm_inst)
1958
1959         # Check that group has been added
1960         self.assertTrue(inst_has_sec_grp(
1961             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1962
1963         # Add security group to instance after activated
1964         self.assertTrue(self.inst_creator.add_security_group(sec_grp))
1965
1966         # Validate that security group has been added
1967         self.assertTrue(inst_has_sec_grp(
1968             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1969
1970
1971 def inst_has_sec_grp(nova, vm_inst, sec_grp_name):
1972     """
1973     Returns true if instance has a security group of a given name
1974     :param nova: the nova client
1975     :param vm_inst: the VmInst domain object
1976     :param sec_grp_name: the name of the security group to validate
1977     :return: T/F
1978     """
1979     sec_grp_names = nova_utils.get_server_security_group_names(nova, vm_inst)
1980     for name in sec_grp_names:
1981         if sec_grp_name == name:
1982             return True
1983     return False
1984
1985
1986 def validate_ssh_client(instance_creator):
1987     """
1988     Returns True if instance_creator returns an SSH client that is valid
1989     :param instance_creator: the object responsible for creating the VM
1990                              instance
1991     :return: T/F
1992     """
1993     ssh_active = instance_creator.vm_ssh_active(block=True)
1994
1995     if ssh_active:
1996         ssh_client = instance_creator.ssh_client()
1997         if ssh_client:
1998             try:
1999                 out = ssh_client.exec_command('pwd')[1]
2000                 channel = out.channel
2001                 in_buffer = channel.in_buffer
2002                 pwd_out = in_buffer.read(1024)
2003                 if not pwd_out or len(pwd_out) < 10:
2004                     return False
2005                 return True
2006             finally:
2007                 ssh_client.close()
2008         else:
2009             return False
2010
2011     return False
2012
2013
2014 class CreateInstanceFromThreePartImage(OSIntegrationTestCase):
2015     """
2016     Test for the CreateInstance class for creating an image from a 3-part image
2017     """
2018
2019     def setUp(self):
2020         """
2021         Instantiates the CreateImage object that is responsible for downloading
2022         and creating an OS image file within OpenStack
2023         """
2024         super(self.__class__, self).__start__()
2025
2026         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
2027         self.image_name = guid
2028         self.vm_inst_name = guid + '-inst'
2029         self.nova = nova_utils.nova_client(self.os_creds)
2030
2031         net_config = openstack_tests.get_priv_net_config(
2032             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
2033             router_name=guid + '-pub-router', external_net=self.ext_net_name)
2034
2035         # Initialize for tearDown()
2036         self.image_creator = None
2037         self.network_creator = None
2038         self.flavor_creator = None
2039         self.inst_creator = None
2040
2041         try:
2042             if self.image_metadata and 'disk_file' in self.image_metadata:
2043                 metadata = self.image_metadata
2044             elif self.image_metadata and 'cirros' in self.image_metadata \
2045                     and 'disk_file' in self.image_metadata['cirros']:
2046                 metadata = self.image_metadata['cirros']
2047             else:
2048                 metadata = {
2049                     'disk_url': openstack_tests.CIRROS_DEFAULT_IMAGE_URL,
2050                     'kernel_url':
2051                         openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL,
2052                     'ramdisk_url':
2053                         openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL}
2054
2055             image_settings = openstack_tests.cirros_image_settings(
2056                 name=self.image_name,
2057                 image_metadata=metadata)
2058
2059             if not image_settings.ramdisk_image_settings or not \
2060                     image_settings.kernel_image_settings:
2061                 logger.warn(
2062                     '3 Part image will not be tested. Image metadata has '
2063                     'overridden this functionality')
2064
2065             self.image_creator = OpenStackImage(self.os_creds, image_settings)
2066             self.image_creator.create()
2067
2068             # Create Flavor
2069             self.flavor_creator = OpenStackFlavor(
2070                 self.admin_os_creds,
2071                 FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10,
2072                              vcpus=2, metadata=self.flavor_metadata))
2073             self.flavor_creator.create()
2074
2075             # Create Network
2076             self.network_creator = OpenStackNetwork(
2077                 self.os_creds, net_config.network_settings)
2078             self.network_creator.create()
2079
2080             self.port_settings = PortSettings(
2081                 name=guid + '-port',
2082                 network_name=net_config.network_settings.name)
2083         except Exception as e:
2084             self.tearDown()
2085             raise e
2086
2087     def tearDown(self):
2088         """
2089         Cleans the created object
2090         """
2091         if self.inst_creator:
2092             try:
2093                 self.inst_creator.clean()
2094             except Exception as e:
2095                 logger.error(
2096                     'Unexpected exception cleaning VM instance with message -'
2097                     ' %s', e)
2098
2099         if self.flavor_creator:
2100             try:
2101                 self.flavor_creator.clean()
2102             except Exception as e:
2103                 logger.error(
2104                     'Unexpected exception cleaning flavor with message - %s',
2105                     e)
2106
2107         if self.network_creator:
2108             try:
2109                 self.network_creator.clean()
2110             except Exception as e:
2111                 logger.error(
2112                     'Unexpected exception cleaning network with message - %s',
2113                     e)
2114
2115         if self.image_creator and not self.image_creator.image_settings.exists:
2116             try:
2117                 self.image_creator.clean()
2118             except Exception as e:
2119                 logger.error(
2120                     'Unexpected exception cleaning image with message - %s', e)
2121
2122         super(self.__class__, self).__clean__()
2123
2124     def test_create_instance_from_three_part_image(self):
2125         """
2126         Tests the creation of an OpenStack instance from a 3-part image.
2127         """
2128         instance_settings = VmInstanceSettings(
2129             name=self.vm_inst_name,
2130             flavor=self.flavor_creator.flavor_settings.name,
2131             port_settings=[self.port_settings])
2132
2133         # The last created image is the main image from which we create the
2134         # instance
2135         self.inst_creator = OpenStackVmInstance(
2136             self.os_creds, instance_settings,
2137             self.image_creator.image_settings)
2138
2139         vm_inst = self.inst_creator.create()
2140         self.assertIsNotNone(vm_inst)
2141         self.assertTrue(self.inst_creator.vm_active(block=True))
2142
2143
2144 class CreateInstanceMockOfflineTests(OSComponentTestCase):
2145     """
2146     Tests the custom image_metadata that can be set by clients for handling
2147     images differently than the default behavior of the existing tests
2148     primarily for offline testing
2149     """
2150
2151     def setUp(self):
2152         """
2153         Instantiates the CreateImage object that is responsible for downloading
2154         and creating an OS image file within OpenStack
2155         """
2156         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
2157
2158         self.tmpDir = 'tmp/' + str(self.guid)
2159         if not os.path.exists(self.tmpDir):
2160             os.makedirs(self.tmpDir)
2161
2162         self.image_name = self.guid + '-image'
2163         self.vm_inst_name = self.guid + '-inst'
2164         self.port_1_name = self.guid + 'port-1'
2165
2166         # Initialize for tearDown()
2167         self.image_creator = None
2168         self.network_creator = None
2169         self.flavor_creator = None
2170         self.inst_creator = None
2171
2172         self.priv_net_config = openstack_tests.get_priv_net_config(
2173             net_name=self.guid + '-priv-net',
2174             subnet_name=self.guid + '-priv-subnet')
2175         self.port_settings = PortSettings(
2176             name=self.port_1_name,
2177             network_name=self.priv_net_config.network_settings.name)
2178
2179         try:
2180             # Download image file
2181             self.image_file = file_utils.download(
2182                 openstack_tests.CIRROS_DEFAULT_IMAGE_URL, self.tmpDir)
2183
2184             # Create Network
2185             self.network_creator = OpenStackNetwork(
2186                 self.os_creds, self.priv_net_config.network_settings)
2187             self.network_creator.create()
2188
2189             # Create Flavor
2190             self.flavor_creator = OpenStackFlavor(
2191                 self.os_creds,
2192                 FlavorConfig(
2193                     name=self.guid + '-flavor-name', ram=256, disk=10,
2194                     vcpus=1))
2195             self.flavor_creator.create()
2196         except Exception as e:
2197             self.tearDown()
2198             raise e
2199
2200     def tearDown(self):
2201         """
2202         Cleans the created object
2203         """
2204         if self.inst_creator:
2205             try:
2206                 self.inst_creator.clean()
2207             except Exception as e:
2208                 logger.error(
2209                     'Unexpected exception cleaning VM instance with message - '
2210                     '%s', e)
2211
2212         if self.network_creator:
2213             try:
2214                 self.network_creator.clean()
2215             except Exception as e:
2216                 logger.error(
2217                     'Unexpected exception cleaning network with message - %s',
2218                     e)
2219
2220         if self.flavor_creator:
2221             try:
2222                 self.flavor_creator.clean()
2223             except Exception as e:
2224                 logger.error(
2225                     'Unexpected exception cleaning flavor with message - %s',
2226                     e)
2227
2228         if self.image_creator:
2229             try:
2230                 self.image_creator.clean()
2231             except Exception as e:
2232                 logger.error(
2233                     'Unexpected exception cleaning image with message - %s', e)
2234
2235         if os.path.exists(self.tmpDir) and os.path.isdir(self.tmpDir):
2236             shutil.rmtree(self.tmpDir)
2237
2238     def test_inst_from_file_image_simple_flat(self):
2239         """
2240         Creates a VM instance from a locally sourced file image using simply
2241         the 'disk_file' attribute vs. using the 'config' option which
2242         completely overrides all image settings
2243         :return: 
2244         """
2245         metadata = {'disk_file': self.image_file.name}
2246
2247         os_image_settings = openstack_tests.cirros_image_settings(
2248             name=self.image_name, image_metadata=metadata)
2249         self.assertEqual(self.image_file.name, os_image_settings.image_file)
2250         self.assertEqual(openstack_tests.CIRROS_USER,
2251                          os_image_settings.image_user)
2252         self.assertIsNone(os_image_settings.url)
2253         self.assertFalse(os_image_settings.exists)
2254         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2255                          os_image_settings.format)
2256
2257         self.assertIsNone(os_image_settings.kernel_image_settings)
2258         self.assertIsNone(os_image_settings.ramdisk_image_settings)
2259
2260         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2261         self.image_creator.create()
2262
2263         instance_settings = VmInstanceSettings(
2264             name=self.vm_inst_name,
2265             flavor=self.flavor_creator.flavor_settings.name,
2266             port_settings=[self.port_settings])
2267         self.inst_creator = OpenStackVmInstance(
2268             self.os_creds, instance_settings,
2269             self.image_creator.image_settings)
2270         self.inst_creator.create()
2271
2272         self.assertTrue(self.inst_creator.vm_active(block=True))
2273
2274     def test_inst_from_file_image_simple_nested(self):
2275         """
2276         Creates a VM instance from a locally sourced file image using simply
2277         the 'disk_file' attribute under 'cirros' vs. using the 'config' option
2278         which completely overrides all image settings
2279         :return: 
2280         """
2281         metadata = {'cirros': {'disk_file': self.image_file.name}}
2282
2283         os_image_settings = openstack_tests.cirros_image_settings(
2284             name=self.image_name, image_metadata=metadata)
2285         self.assertEqual(self.image_file.name, os_image_settings.image_file)
2286         self.assertEqual(openstack_tests.CIRROS_USER,
2287                          os_image_settings.image_user)
2288         self.assertIsNone(os_image_settings.url)
2289         self.assertFalse(os_image_settings.exists)
2290         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2291                          os_image_settings.format)
2292
2293         self.assertIsNone(os_image_settings.kernel_image_settings)
2294         self.assertIsNone(os_image_settings.ramdisk_image_settings)
2295
2296         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2297         self.image_creator.create()
2298
2299         instance_settings = VmInstanceSettings(
2300             name=self.vm_inst_name,
2301             flavor=self.flavor_creator.flavor_settings.name,
2302             port_settings=[self.port_settings])
2303         self.inst_creator = OpenStackVmInstance(
2304             self.os_creds, instance_settings,
2305             self.image_creator.image_settings)
2306         self.inst_creator.create()
2307
2308         self.assertTrue(self.inst_creator.vm_active(block=True))
2309
2310     def test_inst_from_existing(self):
2311         """
2312         Creates a VM instance from a image creator that has been configured to
2313         use an existing image
2314         :return: 
2315         """
2316         os_image_settings = openstack_tests.cirros_image_settings(
2317             name=self.image_name)
2318         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2319         self.image_creator.create()
2320
2321         image_settings = self.image_creator.image_settings
2322         test_image_creator = OpenStackImage(
2323             self.os_creds,
2324             ImageConfig(
2325                 name=image_settings.name, image_user=image_settings.image_user,
2326                 exists=True))
2327         test_image_creator.create()
2328         self.assertEqual(self.image_creator.get_image().id,
2329                          test_image_creator.get_image().id)
2330
2331         instance_settings = VmInstanceSettings(
2332             name=self.vm_inst_name,
2333             flavor=self.flavor_creator.flavor_settings.name,
2334             port_settings=[self.port_settings])
2335         self.inst_creator = OpenStackVmInstance(
2336             self.os_creds, instance_settings,
2337             test_image_creator.image_settings)
2338         self.inst_creator.create()
2339
2340         self.assertTrue(self.inst_creator.vm_active(block=True))
2341
2342     def test_inst_from_file_image_complex(self):
2343         """
2344         Creates a VM instance from a locally sourced file image by overriding
2345         the default settings by using a dict() that can be read in by
2346         ImageSettings
2347         :return: 
2348         """
2349
2350         os_image_settings = openstack_tests.cirros_image_settings(
2351             name=self.image_name)
2352         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2353         self.image_creator.create()
2354
2355         metadata = {
2356             'cirros': {
2357                 'config': {
2358                     'name': os_image_settings.name,
2359                     'image_user': os_image_settings.image_user,
2360                     'exists': True}}}
2361         test_image_settings = openstack_tests.cirros_image_settings(
2362             image_metadata=metadata)
2363         test_image = OpenStackImage(self.os_creds, test_image_settings)
2364         test_image.create()
2365
2366         instance_settings = VmInstanceSettings(
2367             name=self.vm_inst_name,
2368             flavor=self.flavor_creator.flavor_settings.name,
2369             port_settings=[self.port_settings])
2370         self.inst_creator = OpenStackVmInstance(self.os_creds,
2371                                                 instance_settings,
2372                                                 test_image_settings)
2373         self.inst_creator.create()
2374
2375         self.assertTrue(self.inst_creator.vm_active(block=True))
2376
2377     def test_inst_from_file_3part_image_complex(self):
2378         """
2379         Creates a VM instance from a locally sourced file image by overriding
2380         the default settings by using a dict() that can be read in by
2381         ImageSettings
2382         :return: 
2383         """
2384
2385         kernel_file = file_utils.download(
2386             openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL, self.tmpDir)
2387         ramdisk_file = file_utils.download(
2388             openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL, self.tmpDir)
2389
2390         metadata = {
2391             'cirros': {
2392                 'config': {
2393                     'name': self.image_name,
2394                     'image_user': openstack_tests.CIRROS_USER,
2395                     'image_file': self.image_file.name,
2396                     'format': openstack_tests.DEFAULT_IMAGE_FORMAT,
2397                     'kernel_image_settings': {
2398                         'name': self.image_name + '-kernel',
2399                         'image_user': openstack_tests.CIRROS_USER,
2400                         'image_file': kernel_file.name,
2401                         'format': openstack_tests.DEFAULT_IMAGE_FORMAT},
2402                     'ramdisk_image_settings': {
2403                         'name': self.image_name + '-ramdisk',
2404                         'image_user': openstack_tests.CIRROS_USER,
2405                         'image_file': ramdisk_file.name,
2406                         'format': openstack_tests.DEFAULT_IMAGE_FORMAT}}}}
2407
2408         os_image_settings = openstack_tests.cirros_image_settings(
2409             name=self.image_name, image_metadata=metadata)
2410         self.assertEqual(self.image_name, os_image_settings.name)
2411         self.assertEqual(self.image_file.name, os_image_settings.image_file)
2412         self.assertEqual(openstack_tests.CIRROS_USER,
2413                          os_image_settings.image_user)
2414         self.assertIsNone(os_image_settings.url)
2415         self.assertFalse(os_image_settings.exists)
2416         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2417                          os_image_settings.format)
2418
2419         self.assertIsNotNone(os_image_settings.kernel_image_settings)
2420         self.assertEqual(self.image_name + '-kernel',
2421                          os_image_settings.kernel_image_settings.name)
2422         self.assertEqual(kernel_file.name,
2423                          os_image_settings.kernel_image_settings.image_file)
2424         self.assertEqual(openstack_tests.CIRROS_USER,
2425                          os_image_settings.kernel_image_settings.image_user)
2426         self.assertIsNone(os_image_settings.kernel_image_settings.url)
2427         self.assertFalse(os_image_settings.kernel_image_settings.exists)
2428         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2429                          os_image_settings.kernel_image_settings.format)
2430
2431         self.assertIsNotNone(os_image_settings.ramdisk_image_settings)
2432         self.assertEqual(self.image_name + '-ramdisk',
2433                          os_image_settings.ramdisk_image_settings.name)
2434         self.assertEqual(ramdisk_file.name,
2435                          os_image_settings.ramdisk_image_settings.image_file)
2436         self.assertEqual(openstack_tests.CIRROS_USER,
2437                          os_image_settings.ramdisk_image_settings.image_user)
2438         self.assertIsNone(os_image_settings.ramdisk_image_settings.url)
2439         self.assertFalse(os_image_settings.ramdisk_image_settings.exists)
2440         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2441                          os_image_settings.ramdisk_image_settings.format)
2442
2443         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2444         self.image_creator.create()
2445
2446         instance_settings = VmInstanceSettings(
2447             name=self.vm_inst_name,
2448             flavor=self.flavor_creator.flavor_settings.name,
2449             port_settings=[self.port_settings])
2450         self.inst_creator = OpenStackVmInstance(
2451             self.os_creds, instance_settings,
2452             self.image_creator.image_settings)
2453         self.inst_creator.create()
2454
2455         self.assertTrue(self.inst_creator.vm_active(block=True))
2456
2457     def test_inst_from_file_3part_image_simple_flat(self):
2458         """
2459         Creates a VM instance from a 3-part image locally sourced from file
2460         images using simply the 'disk_file', 'kernel_file', and 'ramdisk_file'
2461         attributes vs. using the 'config' option which completely overrides all
2462         image settings
2463         :return: 
2464         """
2465         kernel_file = file_utils.download(
2466             openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL, self.tmpDir)
2467         ramdisk_file = file_utils.download(
2468             openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL, self.tmpDir)
2469
2470         metadata = {'disk_file': self.image_file.name,
2471                     'kernel_file': kernel_file.name,
2472                     'ramdisk_file': ramdisk_file.name}
2473
2474         os_image_settings = openstack_tests.cirros_image_settings(
2475             name=self.image_name, image_metadata=metadata)
2476
2477         self.assertEqual(self.image_name, os_image_settings.name)
2478         self.assertEqual(self.image_file.name, os_image_settings.image_file)
2479         self.assertEqual(openstack_tests.CIRROS_USER,
2480                          os_image_settings.image_user)
2481         self.assertIsNone(os_image_settings.url)
2482         self.assertFalse(os_image_settings.exists)
2483         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2484                          os_image_settings.format)
2485
2486         self.assertIsNotNone(os_image_settings.kernel_image_settings)
2487         self.assertEqual(self.image_name + '-kernel',
2488                          os_image_settings.kernel_image_settings.name)
2489         self.assertEqual(kernel_file.name,
2490                          os_image_settings.kernel_image_settings.image_file)
2491         self.assertEqual(openstack_tests.CIRROS_USER,
2492                          os_image_settings.kernel_image_settings.image_user)
2493         self.assertIsNone(os_image_settings.kernel_image_settings.url)
2494         self.assertFalse(os_image_settings.kernel_image_settings.exists)
2495         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2496                          os_image_settings.kernel_image_settings.format)
2497
2498         self.assertIsNotNone(os_image_settings.ramdisk_image_settings)
2499         self.assertEqual(self.image_name + '-ramdisk',
2500                          os_image_settings.ramdisk_image_settings.name)
2501         self.assertEqual(ramdisk_file.name,
2502                          os_image_settings.ramdisk_image_settings.image_file)
2503         self.assertEqual(openstack_tests.CIRROS_USER,
2504                          os_image_settings.ramdisk_image_settings.image_user)
2505         self.assertIsNone(os_image_settings.ramdisk_image_settings.url)
2506         self.assertFalse(os_image_settings.ramdisk_image_settings.exists)
2507         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2508                          os_image_settings.ramdisk_image_settings.format)
2509
2510         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2511         self.image_creator.create()
2512
2513         self.assertIsNotNone(self.image_creator.get_kernel_image())
2514         self.assertIsNotNone(self.image_creator.get_ramdisk_image())
2515
2516         instance_settings = VmInstanceSettings(
2517             name=self.vm_inst_name,
2518             flavor=self.flavor_creator.flavor_settings.name,
2519             port_settings=[self.port_settings])
2520         self.inst_creator = OpenStackVmInstance(
2521             self.os_creds, instance_settings,
2522             self.image_creator.image_settings)
2523         self.inst_creator.create()
2524
2525         self.assertTrue(self.inst_creator.vm_active(block=True))
2526
2527     def test_inst_from_file_3part_image_simple_nested(self):
2528         """
2529         Creates a VM instance from a 3-part image locally sourced from file
2530         images using simply the 'disk_file', 'kernel_file', and 'ramdisk_file'
2531         attributes under 'cirros' vs. using the 'config' option which
2532         completely overrides all image settings
2533         :return: 
2534         """
2535         kernel_file = file_utils.download(
2536             openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL, self.tmpDir)
2537         ramdisk_file = file_utils.download(
2538             openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL, self.tmpDir)
2539
2540         metadata = {'cirros': {'disk_file': self.image_file.name,
2541                                'kernel_file': kernel_file.name,
2542                                'ramdisk_file': ramdisk_file.name}}
2543
2544         os_image_settings = openstack_tests.cirros_image_settings(
2545             name=self.image_name, image_metadata=metadata)
2546
2547         self.assertEqual(self.image_name, os_image_settings.name)
2548         self.assertEqual(self.image_file.name, os_image_settings.image_file)
2549         self.assertEqual(openstack_tests.CIRROS_USER,
2550                          os_image_settings.image_user)
2551         self.assertIsNone(os_image_settings.url)
2552         self.assertFalse(os_image_settings.exists)
2553         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2554                          os_image_settings.format)
2555
2556         self.assertIsNotNone(os_image_settings.kernel_image_settings)
2557         self.assertEqual(self.image_name + '-kernel',
2558                          os_image_settings.kernel_image_settings.name)
2559         self.assertEqual(kernel_file.name,
2560                          os_image_settings.kernel_image_settings.image_file)
2561         self.assertEqual(openstack_tests.CIRROS_USER,
2562                          os_image_settings.kernel_image_settings.image_user)
2563         self.assertIsNone(os_image_settings.kernel_image_settings.url)
2564         self.assertFalse(os_image_settings.kernel_image_settings.exists)
2565         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2566                          os_image_settings.kernel_image_settings.format)
2567
2568         self.assertIsNotNone(os_image_settings.ramdisk_image_settings)
2569         self.assertEqual(self.image_name + '-ramdisk',
2570                          os_image_settings.ramdisk_image_settings.name)
2571         self.assertEqual(ramdisk_file.name,
2572                          os_image_settings.ramdisk_image_settings.image_file)
2573         self.assertEqual(openstack_tests.CIRROS_USER,
2574                          os_image_settings.ramdisk_image_settings.image_user)
2575         self.assertIsNone(os_image_settings.ramdisk_image_settings.url)
2576         self.assertFalse(os_image_settings.ramdisk_image_settings.exists)
2577         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2578                          os_image_settings.ramdisk_image_settings.format)
2579
2580         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2581         self.image_creator.create()
2582
2583         self.assertIsNotNone(self.image_creator.get_kernel_image())
2584         self.assertIsNotNone(self.image_creator.get_ramdisk_image())
2585
2586         instance_settings = VmInstanceSettings(
2587             name=self.vm_inst_name,
2588             flavor=self.flavor_creator.flavor_settings.name,
2589             port_settings=[self.port_settings])
2590         self.inst_creator = OpenStackVmInstance(
2591             self.os_creds, instance_settings,
2592             self.image_creator.image_settings)
2593         self.inst_creator.create()
2594
2595         self.assertTrue(self.inst_creator.vm_active(block=True))
2596
2597     def test_inst_from_file_3part_image_existing(self):
2598         """
2599         Creates a VM instance from a 3-part image that is existing
2600         :return: 
2601         """
2602         kernel_file = file_utils.download(
2603             openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL, self.tmpDir)
2604         ramdisk_file = file_utils.download(
2605             openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL, self.tmpDir)
2606
2607         metadata = {'cirros': {'disk_file': self.image_file.name,
2608                                'kernel_file': kernel_file.name,
2609                                'ramdisk_file': ramdisk_file.name}}
2610
2611         os_image_settings = openstack_tests.cirros_image_settings(
2612             name=self.image_name, image_metadata=metadata)
2613         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2614         self.image_creator.create()
2615
2616         image_settings = self.image_creator.image_settings
2617         test_image_creator = OpenStackImage(
2618             self.os_creds,
2619             ImageConfig(
2620                 name=image_settings.name, image_user=image_settings.image_user,
2621                 exists=True))
2622         test_image_creator.create()
2623         self.assertEqual(self.image_creator.get_image().id,
2624                          test_image_creator.get_image().id)
2625
2626         instance_settings = VmInstanceSettings(
2627             name=self.vm_inst_name,
2628             flavor=self.flavor_creator.flavor_settings.name,
2629             port_settings=[self.port_settings])
2630         self.inst_creator = OpenStackVmInstance(
2631             self.os_creds, instance_settings,
2632             test_image_creator.image_settings)
2633         self.inst_creator.create()
2634
2635         self.assertTrue(self.inst_creator.vm_active(block=True))
2636
2637
2638 class CreateInstanceTwoNetTests(OSIntegrationTestCase):
2639     """
2640     Tests the ability of two VMs to communicate when attached to separate
2641     private networks that are tied together with a router.
2642     """
2643
2644     def setUp(self):
2645         """
2646         Instantiates the CreateImage object that is responsible for downloading
2647         and creating an OS image file within OpenStack
2648         """
2649         super(self.__class__, self).__start__()
2650
2651         cidr1 = '10.200.201.0/24'
2652         cidr2 = '10.200.202.0/24'
2653         static_gateway_ip1 = '10.200.201.1'
2654         static_gateway_ip2 = '10.200.202.1'
2655         self.ip1 = '10.200.201.5'
2656         self.ip2 = '10.200.202.5'
2657
2658         self.nova = nova_utils.nova_client(self.os_creds)
2659
2660         # Initialize for tearDown()
2661         self.image_creator = None
2662         self.network_creators = list()
2663         self.router_creator = None
2664         self.flavor_creator = None
2665         self.sec_grp_creator = None
2666         self.inst_creators = list()
2667
2668         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
2669         self.vm_inst1_name = self.guid + '-inst1'
2670         self.vm_inst2_name = self.guid + '-inst2'
2671         self.port_1_name = self.guid + '-vm1-port'
2672         self.port_2_name = self.guid + '-vm2-port'
2673         self.net_config_1 = NetworkSettings(
2674             name=self.guid + '-net1',
2675             subnet_settings=[
2676                 create_network.SubnetSettings(
2677                     cidr=cidr1, name=self.guid + '-subnet1',
2678                     gateway_ip=static_gateway_ip1)])
2679         self.net_config_2 = NetworkSettings(
2680             name=self.guid + '-net2',
2681             subnet_settings=[
2682                 create_network.SubnetSettings(
2683                     cidr=cidr2, name=self.guid + '-subnet2',
2684                     gateway_ip=static_gateway_ip2)])
2685
2686         image_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
2687         os_image_settings = openstack_tests.cirros_image_settings(
2688             name=image_name, image_metadata=self.image_metadata)
2689
2690         try:
2691             # Create Image
2692             self.image_creator = OpenStackImage(self.os_creds,
2693                                                 os_image_settings)
2694             self.image_creator.create()
2695
2696             # First network is public
2697             self.network_creators.append(OpenStackNetwork(
2698                 self.os_creds, self.net_config_1))
2699             # Second network is private
2700             self.network_creators.append(OpenStackNetwork(
2701                 self.os_creds, self.net_config_2))
2702             for network_creator in self.network_creators:
2703                 network_creator.create()
2704
2705             port_settings = [
2706                 create_network.PortSettings(
2707                     name=self.guid + '-router-port1',
2708                     ip_addrs=[{
2709                         'subnet_name':
2710                             self.net_config_1.subnet_settings[0].name,
2711                         'ip': static_gateway_ip1
2712                     }],
2713                     network_name=self.net_config_1.name,
2714                     project_name=self.os_creds.project_name),
2715                 create_network.PortSettings(
2716                     name=self.guid + '-router-port2',
2717                     ip_addrs=[{
2718                         'subnet_name':
2719                             self.net_config_2.subnet_settings[0].name,
2720                         'ip': static_gateway_ip2
2721                     }],
2722                     network_name=self.net_config_2.name,
2723                     project_name=self.os_creds.project_name)]
2724
2725             router_settings = RouterConfig(
2726                 name=self.guid + '-pub-router', port_settings=port_settings)
2727             self.router_creator = create_router.OpenStackRouter(
2728                 self.os_creds, router_settings)
2729             self.router_creator.create()
2730
2731             # Create Flavor
2732             self.flavor_creator = OpenStackFlavor(
2733                 self.admin_os_creds,
2734                 FlavorConfig(name=self.guid + '-flavor-name', ram=512,
2735                              disk=10, vcpus=2,
2736                              metadata=self.flavor_metadata))
2737             self.flavor_creator.create()
2738
2739             sec_grp_name = self.guid + '-sec-grp'
2740             rule1 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
2741                                               direction=Direction.ingress,
2742                                               protocol=Protocol.icmp)
2743             self.sec_grp_creator = OpenStackSecurityGroup(
2744                 self.os_creds,
2745                 SecurityGroupSettings(name=sec_grp_name,
2746                                       rule_settings=[rule1]))
2747             self.sec_grp_creator.create()
2748         except:
2749             self.tearDown()
2750             raise
2751
2752     def tearDown(self):
2753         """
2754         Cleans the created objects
2755         """
2756         for inst_creator in self.inst_creators:
2757             try:
2758                 inst_creator.clean()
2759             except Exception as e:
2760                 logger.error(
2761                     'Unexpected exception cleaning VM instance with message '
2762                     '- %s', e)
2763
2764         if self.flavor_creator:
2765             try:
2766                 self.flavor_creator.clean()
2767             except Exception as e:
2768                 logger.error(
2769                     'Unexpected exception cleaning flavor with message - %s',
2770                     e)
2771
2772         if self.router_creator:
2773             try:
2774                 self.router_creator.clean()
2775             except Exception as e:
2776                 logger.error(
2777                     'Unexpected exception cleaning router with message - %s',
2778                     e)
2779
2780         for network_creator in self.network_creators:
2781             try:
2782                 network_creator.clean()
2783             except Exception as e:
2784                 logger.error(
2785                     'Unexpected exception cleaning network with message - %s',
2786                     e)
2787
2788         if self.sec_grp_creator:
2789             try:
2790                 self.sec_grp_creator.clean()
2791             except Exception as e:
2792                 logger.error(
2793                     'Unexpected exception cleaning security group with message'
2794                     ' - %s', e)
2795
2796         if self.image_creator and not self.image_creator.image_settings.exists:
2797             try:
2798                 self.image_creator.clean()
2799             except Exception as e:
2800                 logger.error(
2801                     'Unexpected exception cleaning image with message - %s', e)
2802
2803         super(self.__class__, self).__clean__()
2804
2805     def test_ping_via_router(self):
2806         """
2807         Tests the creation of two OpenStack instances with one port on
2808         different private networks wit a router in between to ensure that they
2809         can ping
2810         through
2811         """
2812         # Create ports/NICs for instance
2813         ports_settings = []
2814         ctr = 1
2815         for network_creator in self.network_creators:
2816             ports_settings.append(PortSettings(
2817                 name=self.guid + '-port-' + str(ctr),
2818                 network_name=network_creator.network_settings.name))
2819             ctr += 1
2820
2821         # Configure instances
2822         instance1_settings = VmInstanceSettings(
2823             name=self.vm_inst1_name,
2824             flavor=self.flavor_creator.flavor_settings.name,
2825             userdata=_get_ping_userdata(self.ip2),
2826             port_settings=[PortSettings(
2827                 name=self.port_1_name,
2828                 ip_addrs=[{
2829                     'subnet_name':
2830                         self.net_config_1.subnet_settings[0].name,
2831                     'ip': self.ip1
2832                 }],
2833                 network_name=self.network_creators[0].network_settings.name)])
2834         instance2_settings = VmInstanceSettings(
2835             name=self.vm_inst2_name,
2836             flavor=self.flavor_creator.flavor_settings.name,
2837             userdata=_get_ping_userdata(self.ip1),
2838             port_settings=[PortSettings(
2839                 name=self.port_2_name,
2840                 ip_addrs=[{
2841                     'subnet_name':
2842                         self.net_config_2.subnet_settings[0].name,
2843                     'ip': self.ip2
2844                 }],
2845                 network_name=self.network_creators[1].network_settings.name)])
2846
2847         # Create instances
2848         self.inst_creators.append(OpenStackVmInstance(
2849             self.os_creds, instance1_settings,
2850             self.image_creator.image_settings))
2851         self.inst_creators.append(OpenStackVmInstance(
2852             self.os_creds, instance2_settings,
2853             self.image_creator.image_settings))
2854
2855         for inst_creator in self.inst_creators:
2856             inst_creator.create(block=True)
2857
2858         # Check for DHCP lease
2859         self.assertTrue(check_dhcp_lease(self.inst_creators[0], self.ip1))
2860         self.assertTrue(check_dhcp_lease(self.inst_creators[1], self.ip2))
2861
2862         # Effectively blocks until VM has been properly activated
2863         self.assertTrue(check_ping(self.inst_creators[0]))
2864         self.assertTrue(check_ping(self.inst_creators[1]))
2865
2866
2867 class CreateInstanceVolumeTests(OSIntegrationTestCase):
2868     """
2869     Simple instance creation with an attached volume
2870     """
2871
2872     def setUp(self):
2873         """
2874         Instantiates the CreateImage object that is responsible for downloading
2875         and creating an OS image file
2876         within OpenStack
2877         """
2878         super(self.__class__, self).__start__()
2879
2880         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
2881         self.vm_inst_name = guid + '-inst'
2882         self.nova = nova_utils.nova_client(self.os_creds)
2883         os_image_settings = openstack_tests.cirros_image_settings(
2884             name=guid + '-image', image_metadata=self.image_metadata)
2885
2886         net_config = openstack_tests.get_priv_net_config(
2887             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
2888             router_name=guid + '-pub-router', external_net=self.ext_net_name)
2889
2890         self.volume_settings1 = VolumeConfig(
2891             name=self.__class__.__name__ + '-' + str(guid) + '-1')
2892         self.volume_settings2 = VolumeConfig(
2893             name=self.__class__.__name__ + '-' + str(guid) + '-2')
2894
2895         # Initialize for tearDown()
2896         self.image_creator = None
2897         self.flavor_creator = None
2898
2899         self.network_creator = None
2900         self.inst_creator = None
2901         self.volume_creator1 = None
2902         self.volume_creator2 = None
2903
2904         try:
2905             # Create Image
2906             self.image_creator = OpenStackImage(self.os_creds,
2907                                                 os_image_settings)
2908             self.image_creator.create()
2909
2910             # Create Flavor
2911             self.flavor_creator = OpenStackFlavor(
2912                 self.admin_os_creds,
2913                 FlavorConfig(name=guid + '-flavor-name', ram=256, disk=1,
2914                              vcpus=2, metadata=self.flavor_metadata))
2915             self.flavor_creator.create()
2916
2917             # Create Network
2918             self.network_creator = OpenStackNetwork(
2919                 self.os_creds, net_config.network_settings)
2920             self.network_creator.create()
2921
2922             self.port_settings = PortSettings(
2923                 name=guid + '-port',
2924                 network_name=net_config.network_settings.name)
2925
2926             self.volume_creator1 = OpenStackVolume(
2927                 self.os_creds, self.volume_settings1)
2928             self.volume_creator1.create(block=True)
2929
2930             self.volume_creator2 = OpenStackVolume(
2931                 self.os_creds, self.volume_settings2)
2932             self.volume_creator2.create(block=True)
2933
2934         except Exception as e:
2935             self.tearDown()
2936             raise e
2937
2938     def tearDown(self):
2939         """
2940         Cleans the created object
2941         """
2942         if self.inst_creator:
2943             try:
2944                 self.inst_creator.clean()
2945             except Exception as e:
2946                 logger.error(
2947                     'Unexpected exception cleaning VM instance with message '
2948                     '- %s', e)
2949
2950         if self.flavor_creator:
2951             try:
2952                 self.flavor_creator.clean()
2953             except Exception as e:
2954                 logger.error(
2955                     'Unexpected exception cleaning flavor with message - %s',
2956                     e)
2957
2958         if self.network_creator:
2959             try:
2960                 self.network_creator.clean()
2961             except Exception as e:
2962                 logger.error(
2963                     'Unexpected exception cleaning network with message - %s',
2964                     e)
2965
2966         if self.volume_creator2:
2967             try:
2968                 self.volume_creator2.clean()
2969             except Exception as e:
2970                 logger.error(
2971                     'Unexpected exception cleaning volume with message - %s',
2972                     e)
2973
2974         if self.volume_creator1:
2975             try:
2976                 self.volume_creator1.clean()
2977             except Exception as e:
2978                 logger.error(
2979                     'Unexpected exception cleaning volume with message - %s',
2980                     e)
2981
2982         if self.image_creator and not self.image_creator.image_settings.exists:
2983             try:
2984                 self.image_creator.clean()
2985             except Exception as e:
2986                 logger.error(
2987                     'Unexpected exception cleaning image with message - %s', e)
2988
2989         super(self.__class__, self).__clean__()
2990
2991     def test_create_instance_with_one_volume(self):
2992         """
2993         Tests the creation of an OpenStack instance with a single volume.
2994         """
2995         instance_settings = VmInstanceSettings(
2996             name=self.vm_inst_name,
2997             flavor=self.flavor_creator.flavor_settings.name,
2998             port_settings=[self.port_settings],
2999             volume_names=[self.volume_settings1.name])
3000
3001         self.inst_creator = OpenStackVmInstance(
3002             self.os_creds, instance_settings,
3003             self.image_creator.image_settings)
3004
3005         vm_inst = self.inst_creator.create(block=True)
3006         self.assertIsNotNone(nova_utils.get_server(
3007             self.nova, vm_inst_settings=instance_settings))
3008
3009         self.assertIsNotNone(vm_inst)
3010         self.assertEqual(1, len(vm_inst.volume_ids))
3011         self.assertEqual(self.volume_creator1.get_volume().id,
3012                          vm_inst.volume_ids[0]['id'])
3013
3014     def test_create_instance_with_two_volumes(self):
3015         """
3016         Tests the creation of an OpenStack instance with a single volume.
3017         """
3018         instance_settings = VmInstanceSettings(
3019             name=self.vm_inst_name,
3020             flavor=self.flavor_creator.flavor_settings.name,
3021             port_settings=[self.port_settings],
3022             volume_names=[self.volume_settings1.name,
3023                           self.volume_settings2.name])
3024
3025         self.inst_creator = OpenStackVmInstance(
3026             self.os_creds, instance_settings,
3027             self.image_creator.image_settings)
3028
3029         vm_inst = self.inst_creator.create(block=True)
3030         self.assertIsNotNone(nova_utils.get_server(
3031             self.nova, vm_inst_settings=instance_settings))
3032
3033         self.assertIsNotNone(vm_inst)
3034         self.assertEqual(2, len(vm_inst.volume_ids))
3035         self.assertEqual(self.volume_creator1.get_volume().id,
3036                          vm_inst.volume_ids[0]['id'])
3037         self.assertEqual(self.volume_creator2.get_volume().id,
3038                          vm_inst.volume_ids[1]['id'])
3039
3040
3041 def check_dhcp_lease(inst_creator, ip, timeout=160):
3042     """
3043     Returns true if the expected DHCP lease has been acquired
3044     :param inst_creator: the SNAPS OpenStackVmInstance object
3045     :param ip: the IP address to look for
3046     :param timeout: how long to query for IP address
3047     :return:
3048     """
3049     found = False
3050     start_time = time.time()
3051
3052     logger.info("Looking for IP %s in the console log" % ip)
3053     full_log = ''
3054     while timeout > time.time() - start_time:
3055         output = inst_creator.get_console_output()
3056         full_log = full_log + output
3057         if re.search(ip, output):
3058             logger.info('DHCP lease obtained logged in console')
3059             found = True
3060             break
3061
3062     if not found:
3063         logger.error('Full console output -\n' + full_log)
3064     else:
3065         logger.debug('Full console output -\n' + full_log)
3066
3067     return found
3068
3069
3070 def _get_ping_userdata(test_ip):
3071     """
3072     Returns the post VM creation script to be added into the VM's userdata
3073     :param test_ip: the IP value to substitute into the script
3074     :return: the bash script contents
3075     """
3076     if test_ip:
3077         return ("#!/bin/sh\n\n"
3078                 "while true; do\n"
3079                 " ping -c 1 %s 2>&1 >/dev/null\n"
3080                 " RES=$?\n"
3081                 " if [ \"Z$RES\" = \"Z0\" ] ; then\n"
3082                 "  echo 'vPing OK'\n"
3083                 "  break\n"
3084                 " else\n"
3085                 "  echo 'vPing KO'\n"
3086                 " fi\n"
3087                 " sleep 1\n"
3088                 "done\n" % test_ip)
3089     return None
3090
3091
3092 def check_ping(vm_creator, timeout=160):
3093     """
3094     Check for VM for ping result
3095     """
3096     tries = 0
3097
3098     while tries < timeout:
3099         time.sleep(1)
3100         p_console = vm_creator.get_console_output()
3101         if "vPing OK" in p_console:
3102             return True
3103         elif "failed to read iid from metadata" in p_console or tries > 5:
3104             return False
3105         tries += 1
3106
3107     return False