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