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