Auto Generated INFO.yaml file
[snaps.git] / snaps / openstack / utils / tests / nova_utils_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 time
17 import uuid
18
19 import os
20
21 from snaps import file_utils
22 from snaps.config.flavor import FlavorConfig
23 from snaps.config.network import PortConfig
24 from snaps.config.vm_inst import VmInstanceConfig
25 from snaps.config.volume import VolumeConfig
26 from snaps.openstack import create_instance
27 from snaps.openstack.create_flavor import OpenStackFlavor
28 from snaps.openstack.create_image import OpenStackImage
29 from snaps.openstack.create_instance import OpenStackVmInstance
30 from snaps.openstack.create_network import OpenStackNetwork
31 from snaps.openstack.create_volume import OpenStackVolume
32 from snaps.openstack.tests import openstack_tests
33 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
34 from snaps.openstack.utils import (
35     nova_utils, neutron_utils, glance_utils, cinder_utils)
36
37 __author__ = 'spisarski'
38
39 logger = logging.getLogger('nova_utils_tests')
40
41
42 class NovaSmokeTests(OSComponentTestCase):
43     """
44     Tests to ensure that the nova client can communicate with the cloud
45     """
46
47     def test_nova_connect_success(self):
48         """
49         Tests to ensure that the proper credentials can connect.
50         """
51         nova = nova_utils.nova_client(self.os_creds)
52
53         # This should not throw an exception
54         nova.flavors.list()
55
56     def test_nova_get_hypervisor_hosts(self):
57         """
58         Tests to ensure that get_hypervisors() function works.
59         """
60         nova = nova_utils.nova_client(self.os_creds)
61
62         hosts = nova_utils.get_hypervisor_hosts(nova)
63         # This should not throw an exception
64         self.assertGreaterEqual(len(hosts), 1)
65
66     def test_nova_connect_fail(self):
67         """
68         Tests to ensure that the improper credentials cannot connect.
69         """
70         from snaps.openstack.os_credentials import OSCreds
71
72         nova = nova_utils.nova_client(
73             OSCreds(username='user', password='pass',
74                     auth_url=self.os_creds.auth_url,
75                     project_name=self.os_creds.project_name,
76                     proxy_settings=self.os_creds.proxy_settings))
77
78         # This should throw an exception
79         with self.assertRaises(Exception):
80             nova.flavors.list()
81
82
83 class NovaUtilsKeypairTests(OSComponentTestCase):
84     """
85     Test basic nova keypair functionality
86     """
87
88     def setUp(self):
89         """
90         Instantiates the CreateImage object that is responsible for downloading
91         and creating an OS image file within OpenStack
92         """
93         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
94         self.priv_key_file_path = 'tmp/' + guid
95         self.pub_key_file_path = self.priv_key_file_path + '.pub'
96
97         self.nova = nova_utils.nova_client(self.os_creds)
98         self.keys = nova_utils.create_keys()
99         self.public_key = nova_utils.public_key_openssh(self.keys)
100         self.keypair_name = guid
101         self.keypair = None
102
103     def tearDown(self):
104         """
105         Cleans the image and downloaded image file
106         """
107         if self.keypair:
108             try:
109                 nova_utils.delete_keypair(self.nova, self.keypair)
110             except:
111                 pass
112
113         try:
114             os.chmod(self.priv_key_file_path, 0o777)
115             os.remove(self.priv_key_file_path)
116         except:
117             pass
118
119         try:
120             os.chmod(self.pub_key_file_path, 0o777)
121             os.remove(self.pub_key_file_path)
122         except:
123             pass
124
125     def test_create_keypair(self):
126         """
127         Tests the creation of an OpenStack keypair that does not exist.
128         """
129         self.keypair = nova_utils.upload_keypair(self.nova, self.keypair_name,
130                                                  self.public_key)
131         result = nova_utils.keypair_exists(self.nova, self.keypair)
132         self.assertEqual(self.keypair, result)
133         keypair = nova_utils.get_keypair_by_name(self.nova, self.keypair_name)
134         self.assertEqual(self.keypair, keypair)
135
136     def test_create_delete_keypair(self):
137         """
138         Tests the creation of an OpenStack keypair that does not exist.
139         """
140         self.keypair = nova_utils.upload_keypair(self.nova, self.keypair_name,
141                                                  self.public_key)
142         result = nova_utils.keypair_exists(self.nova, self.keypair)
143         self.assertEqual(self.keypair, result)
144         nova_utils.delete_keypair(self.nova, self.keypair)
145         result2 = nova_utils.keypair_exists(self.nova, self.keypair)
146         self.assertIsNone(result2)
147
148     def test_create_key_from_file(self):
149         """
150         Tests that the generated RSA keys are properly saved to files
151         :return:
152         """
153         file_utils.save_keys_to_files(self.keys, self.pub_key_file_path,
154                                       self.priv_key_file_path)
155         self.keypair = nova_utils.upload_keypair_file(self.nova,
156                                                       self.keypair_name,
157                                                       self.pub_key_file_path)
158         pub_key_file = open(os.path.expanduser(self.pub_key_file_path))
159         pub_key = pub_key_file.read()
160         pub_key_file.close()
161         self.assertEqual(self.keypair.public_key, pub_key)
162
163
164 class NovaUtilsFlavorTests(OSComponentTestCase):
165     """
166     Test basic nova flavor functionality
167     """
168
169     def setUp(self):
170         """
171         Instantiates the CreateImage object that is responsible for downloading
172         and creating an OS image file within OpenStack
173         """
174         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
175         self.flavor_settings = FlavorConfig(
176             name=guid + '-name', flavor_id=guid + '-id', ram=1, disk=1,
177             vcpus=1, ephemeral=1, swap=2, rxtx_factor=3.0, is_public=False)
178         self.nova = nova_utils.nova_client(self.os_creds)
179         self.flavor = None
180
181     def tearDown(self):
182         """
183         Cleans the image and downloaded image file
184         """
185         if self.flavor:
186             try:
187                 nova_utils.delete_flavor(self.nova, self.flavor)
188             except:
189                 pass
190
191     def test_create_flavor(self):
192         """
193         Tests the creation of an OpenStack keypair that does not exist.
194         """
195         self.flavor = nova_utils.create_flavor(self.nova, self.flavor_settings)
196         self.validate_flavor()
197
198     def test_create_delete_flavor(self):
199         """
200         Tests the creation of an OpenStack keypair that does not exist.
201         """
202         self.flavor = nova_utils.create_flavor(self.nova, self.flavor_settings)
203         self.validate_flavor()
204         nova_utils.delete_flavor(self.nova, self.flavor)
205         flavor = nova_utils.get_flavor_by_name(self.nova,
206                                                self.flavor_settings.name)
207         self.assertIsNone(flavor)
208
209     def validate_flavor(self):
210         """
211         Validates the flavor_settings against the OpenStack flavor object
212         """
213         self.assertIsNotNone(self.flavor)
214         self.assertEqual(self.flavor_settings.name, self.flavor.name)
215         self.assertEqual(self.flavor_settings.flavor_id, self.flavor.id)
216         self.assertEqual(self.flavor_settings.ram, self.flavor.ram)
217         self.assertEqual(self.flavor_settings.disk, self.flavor.disk)
218         self.assertEqual(self.flavor_settings.vcpus, self.flavor.vcpus)
219         self.assertEqual(self.flavor_settings.ephemeral, self.flavor.ephemeral)
220
221         if self.flavor_settings.swap == 0:
222             self.assertEqual('', self.flavor.swap)
223         else:
224             self.assertEqual(self.flavor_settings.swap, self.flavor.swap)
225
226         self.assertEqual(self.flavor_settings.rxtx_factor,
227                          self.flavor.rxtx_factor)
228         self.assertEqual(self.flavor_settings.is_public, self.flavor.is_public)
229
230
231 class NovaUtilsInstanceTests(OSComponentTestCase):
232     """
233     Tests the creation of VM instances via nova_utils.py
234     """
235
236     def setUp(self):
237         """
238         Setup objects required by VM instances
239         :return:
240         """
241
242         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
243
244         self.nova = nova_utils.nova_client(self.os_creds)
245         self.neutron = neutron_utils.neutron_client(self.os_creds)
246         self.glance = glance_utils.glance_client(self.os_creds)
247
248         self.image_creator = None
249         self.network_creator = None
250         self.flavor_creator = None
251         self.port = None
252         self.vm_inst = None
253
254         try:
255             image_settings = openstack_tests.cirros_image_settings(
256                 name=guid + '-image', image_metadata=self.image_metadata)
257             self.image_creator = OpenStackImage(
258                 self.os_creds, image_settings=image_settings)
259             self.image_creator.create()
260
261             network_settings = openstack_tests.get_priv_net_config(
262                 guid + '-net', guid + '-subnet').network_settings
263             self.network_creator = OpenStackNetwork(
264                 self.os_creds, network_settings)
265             self.network_creator.create()
266
267             self.flavor_creator = OpenStackFlavor(
268                 self.os_creds,
269                 FlavorConfig(
270                     name=guid + '-flavor-name', ram=256, disk=10, vcpus=1))
271             self.flavor_creator.create()
272
273             port_settings = PortConfig(
274                 name=guid + '-port', network_name=network_settings.name)
275             self.port = neutron_utils.create_port(
276                 self.neutron, self.os_creds, port_settings)
277
278             self.instance_settings = VmInstanceConfig(
279                 name=guid + '-vm_inst',
280                 flavor=self.flavor_creator.flavor_settings.name,
281                 port_settings=[port_settings])
282         except:
283             self.tearDown()
284             raise
285
286     def tearDown(self):
287         """
288         Cleanup deployed resources
289         :return:
290         """
291         if self.vm_inst:
292             try:
293                 nova_utils.delete_vm_instance(self.nova, self.vm_inst)
294             except:
295                 pass
296         if self.port:
297             try:
298                 neutron_utils.delete_port(self.neutron, self.port)
299             except:
300                 pass
301         if self.flavor_creator:
302             try:
303                 self.flavor_creator.clean()
304             except:
305                 pass
306         if self.network_creator:
307             try:
308                 self.network_creator.clean()
309             except:
310                 pass
311         if self.image_creator:
312             try:
313                 self.image_creator.clean()
314             except:
315                 pass
316
317     def test_create_instance(self):
318         """
319         Tests the nova_utils.create_server() method
320         :return:
321         """
322
323         self.vm_inst = nova_utils.create_server(
324             self.nova, self.neutron, self.glance, self.instance_settings,
325             self.image_creator.image_settings)
326
327         self.assertIsNotNone(self.vm_inst)
328
329         # Wait until instance is ACTIVE
330         iters = 0
331         active = False
332         while iters < 60:
333             if create_instance.STATUS_ACTIVE == nova_utils.get_server_status(
334                     self.nova, self.vm_inst):
335                 active = True
336                 break
337
338             time.sleep(3)
339             iters += 1
340
341         self.assertTrue(active)
342         vm_inst = nova_utils.get_latest_server_object(
343             self.nova, self.neutron, self.vm_inst)
344
345         self.assertEqual(self.vm_inst.name, vm_inst.name)
346         self.assertEqual(self.vm_inst.id, vm_inst.id)
347
348
349 class NovaUtilsInstanceVolumeTests(OSComponentTestCase):
350     """
351     Tests the creation of VM instances via nova_utils.py
352     """
353
354     def setUp(self):
355         """
356         Setup objects required by VM instances
357         :return:
358         """
359
360         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
361
362         self.nova = nova_utils.nova_client(self.os_creds)
363         self.cinder = cinder_utils.cinder_client(self.os_creds)
364
365         self.image_creator = None
366         self.network_creator = None
367         self.flavor_creator = None
368         self.volume_creator = None
369         self.instance_creator = None
370
371         try:
372             image_settings = openstack_tests.cirros_image_settings(
373                 name=guid + '-image', image_metadata=self.image_metadata)
374             self.image_creator = OpenStackImage(
375                 self.os_creds, image_settings=image_settings)
376             self.image_creator.create()
377
378             network_settings = openstack_tests.get_priv_net_config(
379                 guid + '-net', guid + '-subnet').network_settings
380             self.network_creator = OpenStackNetwork(
381                 self.os_creds, network_settings)
382             self.network_creator.create()
383
384             self.flavor_creator = OpenStackFlavor(
385                 self.os_creds,
386                 FlavorConfig(
387                     name=guid + '-flavor-name', ram=256, disk=10, vcpus=1))
388             self.flavor_creator.create()
389
390             # Create Volume
391             volume_settings = VolumeConfig(
392                 name=self.__class__.__name__ + '-' + str(guid))
393             self.volume_creator = OpenStackVolume(
394                 self.os_creds, volume_settings)
395             self.volume_creator.create(block=True)
396
397             port_settings = PortConfig(
398                 name=guid + '-port', network_name=network_settings.name)
399             instance_settings = VmInstanceConfig(
400                 name=guid + '-vm_inst',
401                 flavor=self.flavor_creator.flavor_settings.name,
402                 port_settings=[port_settings])
403             self.instance_creator = OpenStackVmInstance(
404                 self.os_creds, instance_settings, image_settings)
405             self.instance_creator.create(block=True)
406         except:
407             self.tearDown()
408             raise
409
410     def tearDown(self):
411         """
412         Cleanup deployed resources
413         :return:
414         """
415         if self.instance_creator:
416             try:
417                 self.instance_creator.clean()
418             except:
419                 pass
420         if self.volume_creator:
421             try:
422                 self.volume_creator.clean()
423             except:
424                 pass
425         if self.flavor_creator:
426             try:
427                 self.flavor_creator.clean()
428             except:
429                 pass
430         if self.network_creator:
431             try:
432                 self.network_creator.clean()
433             except:
434                 pass
435         if self.image_creator:
436             try:
437                 self.image_creator.clean()
438             except:
439                 pass
440
441     def test_add_remove_volume(self):
442         """
443         Tests the nova_utils.create_server() method
444         :return:
445         """
446
447         self.assertIsNotNone(self.volume_creator.get_volume())
448         self.assertEqual(0, len(self.volume_creator.get_volume().attachments))
449
450         # Attach volume to VM
451         neutron = neutron_utils.neutron_client(self.os_creds)
452         nova_utils.attach_volume(
453             self.nova, neutron, self.instance_creator.get_vm_inst(),
454             self.volume_creator.get_volume(), 120)
455
456         vol_attach = cinder_utils.get_volume_by_id(
457             self.cinder, self.volume_creator.get_volume().id)
458         vm_attach = nova_utils.get_server_object_by_id(
459             self.nova, neutron, self.instance_creator.get_vm_inst().id)
460
461         # Detach volume to VM
462         nova_utils.detach_volume(
463             self.nova, neutron, self.instance_creator.get_vm_inst(),
464             self.volume_creator.get_volume(), 120)
465
466         vol_detach = cinder_utils.get_volume_by_id(
467             self.cinder, self.volume_creator.get_volume().id)
468         vm_detach = nova_utils.get_server_object_by_id(
469             self.nova, neutron, self.instance_creator.get_vm_inst().id)
470
471         # Validate Attachment
472         self.assertIsNotNone(vol_attach)
473         self.assertEqual(self.volume_creator.get_volume().id, vol_attach.id)
474         self.assertEqual(1, len(vol_attach.attachments))
475         self.assertEqual(vm_attach.volume_ids[0]['id'],
476                          vol_attach.attachments[0]['volume_id'])
477
478         # Validate Detachment
479         self.assertIsNotNone(vol_detach)
480         self.assertEqual(self.volume_creator.get_volume().id, vol_detach.id)
481         self.assertEqual(0, len(vol_detach.attachments))
482         self.assertEqual(0, len(vm_detach.volume_ids))