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