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