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