Merge "Bug 129 RIFT-15122"
[osm/SO.git] / rwcal / test / test_rwcal_openstack.py
1
2 #
3 # Copyright 2016 RIFT.IO Inc
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 import datetime
19 import logging
20 import time
21 import unittest
22 import hashlib
23 import novaclient.exceptions as nova_exception
24 import paramiko
25 import rw_peas
26 import rwlogger
27 from keystoneclient import v3 as ksclient
28
29 from gi.repository import RwcalYang
30 from gi.repository.RwTypes import RwStatus
31 from rift.rwcal.openstack.openstack_drv import KeystoneDriver, NovaDriver, KeystoneDriverV3, KeystoneDriverV2
32
33 logger = logging.getLogger('rwcal-openstack')
34
35 #
36 # Important information about openstack installation. This needs to be manually verified
37 #
38 openstack_info = {
39 'username' : 'pluto',
40 'password' : 'mypasswd',
41 'auth_url' : 'http://10.66.4.17:5000/v3/',
42 'project_name' : 'demo',
43 'mgmt_network' : 'private',
44 'reserved_flavor' : 'm1.medium',
45 'reserved_image' : 'Fedora-x86_64-20-20131211.1-sda-ping.qcow2',
46 'physical_network' : None,
47 'network_type' : None,
48 'segmentation_id' : None,
49 'user_domain_name' : 'default',
50 'project_domain_name': 'default'
51 }
52
53 openstack_V3_info = {
54 'username' : 'riftdev_admin',
55 'password' : 'mypasswd',
56 'auth_url' : 'http://10.68.0.11:5000/v3/',
57 'project_name' : 'demov3',
58 'mgmt_network' : 'center',
59 'physical_network' : None,
60 'network_type' : None,
61 'segmentation_id' : None,
62 'user_domain_name' : 'riftdev',
63 'project_domain_name': 'riftdev'
64 }
65
66
67 def get_cal_account():
68 """
69 Creates an object for class RwcalYang.CloudAccount()
70 """
71 account = RwcalYang.CloudAccount()
72 account.name = "Gruntxx"
73 account.account_type = "openstack"
74 account.openstack.key = openstack_info['username']
75 account.openstack.secret = openstack_info['password']
76 account.openstack.auth_url = openstack_info['auth_url']
77 account.openstack.tenant = openstack_info['project_name']
78 account.openstack.mgmt_network = openstack_info['mgmt_network']
79 account.openstack.user_domain = openstack_info['user_domain_name']
80 account.openstack.project_domain = openstack_info['project_domain_name']
81 return account
82
83 def get_cal_plugin():
84 """
85 Loads rw.cal plugin via libpeas
86 """
87 plugin = rw_peas.PeasPlugin('rwcal_openstack', 'RwCal-1.0')
88 engine, info, extension = plugin()
89
90 # Get the RwLogger context
91 rwloggerctx = rwlogger.RwLog.Ctx.new("Cal-Log")
92
93 cal = plugin.get_interface("Cloud")
94 try:
95 rc = cal.init(rwloggerctx)
96 assert rc == RwStatus.SUCCESS
97 except:
98 logger.error("ERROR:Cal plugin instantiation failed. Aborting tests")
99 else:
100 logger.info("Openstack Cal plugin successfully instantiated")
101 return cal
102
103
104 class OpenStackTest(unittest.TestCase):
105 NodeID = "123456789012345" # Some random number to test VM tagging
106 MemoryPageSize = "LARGE"
107 CpuPolicy = "DEDICATED"
108 CpuThreadPolicy = "SEPARATE"
109 CpuThreads = 1
110 NumaNodeCount = 2
111 HostTrust = "trusted"
112 PCIPassThroughAlias = "PCI_10G_ALIAS"
113 SEG_ID = openstack_info['segmentation_id']
114
115 def setUp(self):
116 """
117 Assumption:
118 - It is assumed that openstack install has a flavor and image precreated.
119 - Flavor_name: x1.xlarge
120 - Image_name : rwimage
121
122 If these resources are not then this test will fail.
123 """
124 self._acct = get_cal_account()
125 logger.info("Openstack-CAL-Test: setUp")
126 self.cal = get_cal_plugin()
127 logger.info("Openstack-CAL-Test: setUpEND")
128
129 # First check for VM Flavor and Image and get the corresponding IDs
130 rc, rs = self.cal.get_flavor_list(self._acct)
131 self.assertEqual(rc, RwStatus.SUCCESS)
132
133 flavor_list = [ flavor for flavor in rs.flavorinfo_list if flavor.name == openstack_info['reserved_flavor'] ]
134 self.assertNotEqual(len(flavor_list), 0)
135 self._flavor = flavor_list[0]
136
137 rc, rs = self.cal.get_image_list(self._acct)
138 self.assertEqual(rc, RwStatus.SUCCESS)
139
140 image_list = [ image for image in rs.imageinfo_list if image.name == openstack_info['reserved_image'] ]
141 self.assertNotEqual(len(image_list), 0)
142 self._image = image_list[0]
143
144 rc, rs = self.cal.get_network_list(self._acct)
145 self.assertEqual(rc, RwStatus.SUCCESS)
146 networks = [ network for network in rs.networkinfo_list if ((network.network_name == 'rift.cal.unittest.network') or ('rift.cal.virtual_link' in network.network_name) ) ]
147 for network in networks:
148 logger.debug("Openstack-CAL-Test: Deleting old VL %s", network.network_id)
149 self.cal.delete_virtual_link(self._acct, network.network_id)
150
151 def tearDown(self):
152 logger.info("Openstack-CAL-Test: tearDown")
153
154
155 def _md5(fname, blksize=1048576):
156 hash_md5 = hashlib.md5()
157 with open(fname, "rb") as f:
158 for chunk in iter(lambda: f.read(blksize), b""):
159 hash_md5.update(chunk)
160 return hash_md5.hexdigest()
161
162 @unittest.skip("Skipping test_list_flavors")
163 def test_list_flavor(self):
164 """
165 List existing flavors from openstack installation
166 """
167 logger.info("Openstack-CAL-Test: Starting List Flavors Test")
168 rc, rsp = self.cal.get_flavor_list(self._acct)
169 self.assertEqual(rc, RwStatus.SUCCESS)
170 logger.info("Openstack-CAL-Test: Received %d flavors" %(len(rsp.flavorinfo_list)))
171 for flavor in rsp.flavorinfo_list:
172 rc, flv = self.cal.get_flavor(self._acct, flavor.id)
173 self.assertEqual(rc, RwStatus.SUCCESS)
174 self.assertEqual(flavor.id, flv.id)
175
176 @unittest.skip("Skipping test_list_images")
177 def test_list_images(self):
178 """
179 List existing images from openstack installation
180 """
181 logger.info("Openstack-CAL-Test: Starting List Images Test")
182 rc, rsp = self.cal.get_image_list(self._acct)
183 self.assertEqual(rc, RwStatus.SUCCESS)
184 logger.info("Openstack-CAL-Test: Received %d images" %(len(rsp.imageinfo_list)))
185 #for image in rsp.imageinfo_list:
186 # rc, img = self.cal.get_image(self._acct, image.id)
187 # self.assertEqual(rc, RwStatus.SUCCESS)
188 # self.assertEqual(image.id, img.id)
189
190 @unittest.skip("Skipping test_list_vms")
191 def test_list_vms(self):
192 """
193 List existing VMs from openstack installation
194 """
195 logger.info("Openstack-CAL-Test: Starting List VMs Test")
196 rc, rsp = self.cal.get_vm_list(self._acct)
197 self.assertEqual(rc, RwStatus.SUCCESS)
198 logger.info("Openstack-CAL-Test: Received %d VMs" %(len(rsp.vminfo_list)))
199 for vm in rsp.vminfo_list:
200 rc, server = self.cal.get_vm(self._acct, vm.vm_id)
201 self.assertEqual(vm.vm_id, server.vm_id)
202
203 @unittest.skip("Skipping test_list_networks")
204 def test_list_networks(self):
205 """
206 List existing Network from openstack installation
207 """
208 logger.info("Openstack-CAL-Test: Starting List Networks Test")
209 rc, rsp = self.cal.get_network_list(self._acct)
210 self.assertEqual(rc, RwStatus.SUCCESS)
211 logger.info("Openstack-CAL-Test: Received %d Networks" %(len(rsp.networkinfo_list)))
212 for network in rsp.networkinfo_list:
213 rc, net = self.cal.get_network(self._acct, network.network_id)
214 self.assertEqual(network.network_id, net.network_id)
215
216 @unittest.skip("Skipping test_list_ports")
217 def test_list_ports(self):
218 """
219 List existing Ports from openstack installation
220 """
221 logger.info("Openstack-CAL-Test: Starting List Ports Test")
222 rc, rsp = self.cal.get_port_list(self._acct)
223 self.assertEqual(rc, RwStatus.SUCCESS)
224 assert(rc == RwStatus.SUCCESS)
225 logger.info("Openstack-CAL-Test: Received %d Ports" %(len(rsp.portinfo_list)))
226 for port in rsp.portinfo_list:
227 rc, p = self.cal.get_port(self._acct, port.port_id)
228 self.assertEqual(port.port_id, p.port_id)
229
230 def _get_image_info_request(self):
231 """
232 Returns request object of type RwcalYang.ImageInfoItem()
233 """
234 img = RwcalYang.ImageInfoItem()
235 img.name = "rift.cal.unittest.image"
236 img.location = '/net/sharedfiles/home1/common/vm/rift-root-latest.qcow2'
237 img.disk_format = "qcow2"
238 img.container_format = "bare"
239 img.checksum = self._md5(img.location)
240 return img
241
242 def _get_image_info(self, img_id):
243 """
244 Checks the image status until it becomes active or timeout occurs (100sec)
245 Returns the image_info dictionary
246 """
247 rs = None
248 rc = None
249 for i in range(100):
250 rc, rs = self.cal.get_image(self._acct, img_id)
251 self.assertEqual(rc, RwStatus.SUCCESS)
252 logger.info("Openstack-CAL-Test: Image (image_id: %s) reached state : %s" %(img_id, rs.state))
253 if rs.state == 'active':
254 break
255 else:
256 time.sleep(2) # Sleep for a second
257 return rs
258
259 @unittest.skip("Skipping test_create_delete_image")
260 def test_create_delete_image(self):
261 """
262 Create/Query/Delete a new image in openstack installation
263 """
264 logger.info("Openstack-CAL-Test: Starting Image create test")
265 img = self._get_image_info_request()
266 rc, img_id = self.cal.create_image(self._acct, img)
267 logger.info("Openstack-CAL-Test: Created Image with image_id: %s" %(img_id))
268 self.assertEqual(rc, RwStatus.SUCCESS)
269 img_info = self._get_image_info(img_id)
270 self.assertNotEqual(img_info, None)
271 self.assertEqual(img_id, img_info.id)
272 logger.info("Openstack-CAL-Test: Image (image_id: %s) reached state : %s" %(img_id, img_info.state))
273 self.assertEqual(img_info.has_field('checksum'), True)
274 #self.assertEqual(img_info.checksum, OpenStackTest.IMG_Checksum)
275 logger.info("Openstack-CAL-Test: Initiating Delete Image operation for image_id: %s" %(img_id))
276 rc = self.cal.delete_image(self._acct, img_id)
277 self.assertEqual(rc, RwStatus.SUCCESS)
278 logger.info("Openstack-CAL-Test: Image (image_id: %s) successfully deleted" %(img_id))
279
280 def _get_flavor_info_request(self):
281 """
282 Returns request object of type RwcalYang.FlavorInfoItem()
283 """
284 flavor = RwcalYang.FlavorInfoItem()
285 flavor.name = 'rift.cal.unittest.flavor'
286 flavor.vm_flavor.memory_mb = 16384 # 16GB
287 flavor.vm_flavor.vcpu_count = 4
288 flavor.vm_flavor.storage_gb = 40 # 40GB
289 flavor.guest_epa.mempage_size = OpenStackTest.MemoryPageSize
290 flavor.guest_epa.cpu_pinning_policy = OpenStackTest.CpuPolicy
291 flavor.guest_epa.cpu_thread_pinning_policy = OpenStackTest.CpuThreadPolicy
292 flavor.guest_epa.numa_node_policy.node_cnt = OpenStackTest.NumaNodeCount
293 for i in range(OpenStackTest.NumaNodeCount):
294 node = flavor.guest_epa.numa_node_policy.node.add()
295 node.id = i
296 if i == 0:
297 vcpu = node.vcpu.add()
298 vcpu.id = 0
299 vcpu = node.vcpu.add()
300 vcpu.id = 1
301 elif i == 1:
302 vcpu = node.vcpu.add()
303 vcpu.id = 2
304 vcpu = node.vcpu.add()
305 vcpu.id = 3
306 node.memory_mb = 8196
307 dev = flavor.guest_epa.pcie_device.add()
308 dev.device_id = OpenStackTest.PCIPassThroughAlias
309 dev.count = 1
310 return flavor
311
312 @unittest.skip("Skipping test_create_delete_flavor")
313 def test_create_delete_flavor(self):
314 """
315 Create/Query/Delete a new flavor in openstack installation
316 """
317 logger.info("Openstack-CAL-Test: Starting Image create/delete test")
318
319 ### Delete any previously created flavor with name rift.cal.unittest.flavor
320 rc, rs = self.cal.get_flavor_list(self._acct)
321 self.assertEqual(rc, RwStatus.SUCCESS)
322 flavor_list = [ flavor for flavor in rs.flavorinfo_list if flavor.name == 'rift.cal.unittest.flavor' ]
323 if flavor_list:
324 rc = self.cal.delete_flavor(self._acct, flavor_list[0].id)
325 self.assertEqual(rc, RwStatus.SUCCESS)
326
327 flavor = self._get_flavor_info_request()
328 rc, flavor_id = self.cal.create_flavor(self._acct, flavor)
329 self.assertEqual(rc, RwStatus.SUCCESS)
330
331 logger.info("Openstack-CAL-Test: Created new flavor with flavor_id : %s" %(flavor_id))
332 rc, rs = self.cal.get_flavor(self._acct, flavor_id)
333 self.assertEqual(rc, RwStatus.SUCCESS)
334 self.assertEqual(rs.id, flavor_id)
335
336 # Verify EPA Attributes
337 self.assertEqual(rs.guest_epa.mempage_size, OpenStackTest.MemoryPageSize)
338 self.assertEqual(rs.guest_epa.cpu_pinning_policy, OpenStackTest.CpuPolicy)
339 self.assertEqual(rs.guest_epa.cpu_thread_pinning_policy, OpenStackTest.CpuThreadPolicy)
340 self.assertEqual(rs.guest_epa.numa_node_policy.node_cnt, OpenStackTest.NumaNodeCount)
341 self.assertEqual(len(rs.guest_epa.pcie_device), 1)
342 self.assertEqual(rs.guest_epa.pcie_device[0].device_id, OpenStackTest.PCIPassThroughAlias)
343 self.assertEqual(rs.guest_epa.pcie_device[0].count, 1)
344 logger.info("Openstack-CAL-Test: Initiating delete for flavor_id : %s" %(flavor_id))
345 rc = self.cal.delete_flavor(self._acct, flavor_id)
346 self.assertEqual(rc, RwStatus.SUCCESS)
347 # Check that flavor does not exist anymore in list_flavor
348 rc, rs = self.cal.get_flavor_list(self._acct)
349 self.assertEqual(rc, RwStatus.SUCCESS)
350 flavor_list = [ flavor for flavor in rs.flavorinfo_list if flavor.id == flavor_id ]
351 # Flavor List should be empty
352 self.assertEqual(len(flavor_list), 0)
353 logger.info("Openstack-CAL-Test: Flavor (flavor_id: %s) successfully deleted" %(flavor_id))
354
355 def _get_vm_info_request(self, flavor_id, image_id):
356 """
357 Returns request object of type RwcalYang.VMInfoItem
358 """
359 vm = RwcalYang.VMInfoItem()
360 vm.vm_name = 'rift.cal.unittest.vm'
361 vm.flavor_id = flavor_id
362 vm.image_id = image_id
363 vm.cloud_init.userdata = ''
364 vm.user_tags.node_id = OpenStackTest.NodeID
365 return vm
366
367 def _check_vm_state(self, vm_id, expected_state):
368 """
369 Wait until VM reaches particular state (expected_state).
370 """
371 # Wait while VM goes to required state
372
373 for i in range(50): # 50 poll iterations...
374 rc, rs = self.cal.get_vm(self._acct, vm_id)
375 self.assertEqual(rc, RwStatus.SUCCESS)
376 logger.info("Openstack-CAL-Test: VM vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
377 if rs.state == expected_state:
378 break
379 else:
380 time.sleep(1)
381
382 rc, rs = self.cal.get_vm(self._acct, vm_id)
383 self.assertEqual(rc, RwStatus.SUCCESS)
384 self.assertEqual(rs.state, expected_state)
385
386 def _create_vm(self, flavor, image, port_list = None):
387 """
388 Create VM and perform validity checks
389 """
390 logger.info("Openstack-CAL-Test: Using image : %s and flavor : %s " %(image.name, flavor.name))
391 vm = self._get_vm_info_request(flavor.id, image.id)
392
393 if port_list:
394 for port_id in port_list:
395 port = vm.port_list.add()
396 port.port_id = port_id
397
398 rc, vm_id = self.cal.create_vm(self._acct, vm)
399 self.assertEqual(rc, RwStatus.SUCCESS)
400
401 ### Check if VM creation is successful
402 rc, rs = self.cal.get_vm(self._acct, vm_id)
403 self.assertEqual(rc, RwStatus.SUCCESS)
404 logger.info("Openstack-CAL-Test: Successfully created VM with vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
405
406 ### Ensure the VM state is active
407 self._check_vm_state(vm_id, 'ACTIVE')
408
409 ### Ensure that userdata tags are set as expected
410 rc, rs = self.cal.get_vm(self._acct, vm_id)
411 self.assertEqual(rc, RwStatus.SUCCESS)
412 self.assertEqual(rs.user_tags.has_field('node_id'), True)
413 self.assertEqual(getattr(rs.user_tags, 'node_id'), OpenStackTest.NodeID)
414 logger.info("Openstack-CAL-Test: Successfully verified the user tags for VM-ID: %s" %(vm_id))
415 return rs, vm_id
416
417 def _delete_vm(self, vm_id):
418 """
419 Delete VM and perform validity checks
420 """
421 rc, rs = self.cal.get_vm(self._acct, vm_id)
422 self.assertEqual(rc, RwStatus.SUCCESS)
423
424 logger.info("Openstack-CAL-Test: Initiating VM Delete operation on VM vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
425
426 rc = self.cal.delete_vm(self._acct, vm_id)
427 self.assertEqual(rc, RwStatus.SUCCESS)
428
429 for i in range(50):
430 # Check if VM still exists
431 rc, rs = self.cal.get_vm_list(self._acct)
432 self.assertEqual(rc, RwStatus.SUCCESS)
433 vm_list = [vm for vm in rs.vminfo_list if vm.vm_id == vm_id]
434 if not len(vm_list):
435 break
436
437 rc, rs = self.cal.get_vm_list(self._acct)
438 self.assertEqual(rc, RwStatus.SUCCESS)
439 vm_list = [vm for vm in rs.vminfo_list if vm.vm_id == vm_id]
440 self.assertEqual(len(vm_list), 0)
441 logger.info("Openstack-CAL-Test: VM with vm_id : %s successfully deleted" %(vm_id))
442
443 def _stop_vm(self, vm_id):
444 """
445 Stop VM and perform validity checks
446 """
447 rc, rs = self.cal.get_vm(self._acct, vm_id)
448 self.assertEqual(rc, RwStatus.SUCCESS)
449 logger.info("Openstack-CAL-Test: Initiating Stop VM operation on VM vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
450 rc = self.cal.stop_vm(self._acct, vm_id)
451 self.assertEqual(rc, RwStatus.SUCCESS)
452 ### Ensure that VM state is SHUTOFF
453 self._check_vm_state(vm_id, 'SHUTOFF')
454
455
456 def _start_vm(self, vm_id):
457 """
458 Starts VM and performs validity checks
459 """
460 rc, rs = self.cal.get_vm(self._acct, vm_id)
461 self.assertEqual(rc, RwStatus.SUCCESS)
462 logger.info("Openstack-CAL-Test: Initiating Start VM operation on VM vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
463 rc = self.cal.start_vm(self._acct, vm_id)
464 self.assertEqual(rc, RwStatus.SUCCESS)
465
466 ### Ensure that VM state is ACTIVE
467 self._check_vm_state(vm_id, 'ACTIVE')
468
469
470 def _reboot_vm(self, vm_id):
471 """
472 Reboot VM and perform validity checks
473 """
474 rc, rs = self.cal.get_vm(self._acct, vm_id)
475 self.assertEqual(rc, RwStatus.SUCCESS)
476 logger.info("Openstack-CAL-Test: Initiating Reboot VM operation on VM vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
477 rc = self.cal.reboot_vm(self._acct, vm_id)
478 self.assertEqual(rc, RwStatus.SUCCESS)
479
480 ### Ensure that VM state is ACTIVE
481 self._check_vm_state(vm_id, 'ACTIVE')
482
483 def assert_vm(self, vm_data, flavor):
484 """Verify the newly created VM for attributes specified in the flavor.
485
486 Args:
487 vm_data (VmData): Instance of the newly created VM
488 flavor (FlavorInfoItem): Config flavor.
489 """
490 vm_config = flavor
491
492 # Page size seems to be 4096, regardless of the page size name.
493 page_lookup = {"large": '4096', "small": '4096'}
494 FIELDS = ["vcpus", "cpu_threads", "memory_page_size", "disk",
495 "numa_node_count", "memory", "pci_passthrough_device_list"]
496
497 for field in FIELDS:
498 if field not in vm_config:
499 continue
500
501 vm_value = getattr(vm_data, field)
502 config_value = getattr(vm_config, field)
503
504 if field == "memory_page_size":
505 config_value = page_lookup[config_value]
506
507 if field == "memory":
508 config_value = int(config_value/1000)
509
510 if field == "pci_passthrough_device_list":
511 config_value = len(config_value)
512 vm_value = len(vm_value)
513
514 self.assertEqual(vm_value, config_value)
515
516 @unittest.skip("Skipping test_vm_epa_attributes")
517 def test_vm_epa_attributes(self):
518 """
519 Primary goal: To create a VM with the specified EPA Attributes
520 Secondary goal: To verify flavor creation/delete
521 """
522
523 logger.info("Openstack-CAL-Test: Starting VM(EPA) create/delete test")
524 flavor = self._get_flavor_info_request()
525
526 rc, flavor_id = self.cal.do_create_flavor(self._acct, flavor)
527 self.assertEqual(rc, RwStatus.SUCCESS)
528 flavor.id = flavor_id
529
530 data, vm_id = self._create_vm(flavor, self._image)
531
532 vm_data = VmData(data.host_name, data.management_ip)
533 self.assert_vm(vm_data, flavor)
534
535 self._delete_vm(vm_id)
536
537 rc = self.cal.do_delete_flavor(self._acct, flavor_id)
538 self.assertEqual(rc, RwStatus.SUCCESS)
539
540 @unittest.skip("Skipping test_expiry_token")
541 def test_expiry_token(self):
542 """
543 Primary goal: To verify if we are refreshing the expired tokens.
544 """
545 logger.info("Openstack-CAL-Test: Starting token refresh test")
546 drv = KeystoneDriver(
547 openstack_info['username'],
548 openstack_info['password'],
549 openstack_info['auth_url'],
550 None,
551 openstack_info['project_name'])
552 # Get hold of the client instance need for Token Manager
553 client = drv._get_keystone_connection()
554
555 auth_ref = client.auth_ref
556 token = auth_ref['auth_token']
557
558 # Verify if the newly acquired token works.
559 nova = NovaDriver(drv)
560 flavors = nova.flavor_list()
561 self.assertTrue(len(flavors) > 1)
562
563 # Invalidate the token
564 token_manger = ksclient.tokens.TokenManager(client)
565 token_manger.revoke_token(token)
566
567 time.sleep(10)
568
569 unauth_exp = False
570 try:
571 flavors = nova.flavor_list()
572 print (flavors)
573 except nova_exception.AuthorizationFailure:
574 unauth_exp = True
575
576 self.assertTrue(unauth_exp)
577
578 # Explicitly reset the expire time, to test if we acquire a new token
579 now = datetime.datetime.utcnow()
580 time_str = format(now, "%Y-%m-%dT%H:%M:%S.%fZ")
581 drv._get_keystone_connection().auth_ref['expires_at'] = time_str
582
583 flavors = nova.flavor_list()
584 self.assertTrue(len(flavors) > 1)
585
586 def test_v3_Keystone(self):
587 # Keystone v3 authentication
588 auth_exp = False
589 try:
590 drv = KeystoneDriverV3(openstack_V3_info['username'],
591 openstack_V3_info['password'],
592 openstack_V3_info['auth_url'],
593 openstack_V3_info['project_name'],
594 None,
595 openstack_V3_info['user_domain_name'],
596 openstack_V3_info['project_domain_name'])
597 client = drv._get_keystone_connection()
598 except Exception:
599 auth_exp = True
600 self.assertFalse(auth_exp)
601
602 # Incorrect domain being to passed to v3 Keystone API
603 auth_exp = False
604 try:
605 drv = KeystoneDriverV3(openstack_V3_info['username'],
606 openstack_V3_info['password'],
607 openstack_V3_info['auth_url'],
608 openstack_V3_info['project_name'],
609 None,
610 "DummyDom",
611 openstack_V3_info['project_domain_name'])
612 client = drv._get_keystone_connection()
613 except Exception:
614 auth_exp = True
615 self.assertTrue(auth_exp)
616
617 # Keystone v3 authentication-Backward compatabilty test
618 auth_exp = False
619 try:
620 drv = KeystoneDriverV3(openstack_info['username'],
621 openstack_info['password'],
622 openstack_info['auth_url'],
623 openstack_info['project_name'],
624 None,
625 openstack_info['user_domain_name'],
626 openstack_info['project_domain_name'])
627 client = drv._get_keystone_connection()
628 except Exception:
629 auth_exp = True
630 self.assertFalse(auth_exp)
631
632 # Keystone v3 authentication-Backward compatabilty
633 auth_exp = False
634 try:
635 drv = KeystoneDriverV3(openstack_info['username'],
636 openstack_info['password'],
637 openstack_info['auth_url'],
638 openstack_info['project_name'],
639 None,
640 None,
641 None)
642 client = drv._get_keystone_connection()
643 except Exception:
644 auth_exp = True
645 self.assertFalse(auth_exp)
646
647 # Keystone v2 authentication
648 auth_exp = False
649 try:
650 drv2 = KeystoneDriverV2(
651 openstack_info['username'],
652 openstack_info['password'],
653 'http://10.66.4.17:5000/v2.0',
654 openstack_info['project_name'],
655 None)
656 client = drv2._get_keystone_connection()
657 except Exception:
658 auth_exp = True
659 self.assertFalse(auth_exp)
660
661 @unittest.skip("Skipping test_vm_operations")
662 def test_vm_operations(self):
663 """
664 Primary goal: Create/Query/Delete VM in openstack installation.
665 Secondary goal: VM pause/resume operations on VM.
666
667 """
668 logger.info("Openstack-CAL-Test: Starting VM Operations test")
669
670 # Create VM
671 data, vm_id = self._create_vm(self._flavor, self._image)
672
673 # Stop VM
674 self._stop_vm(vm_id)
675 # Start VM
676 self._start_vm(vm_id)
677
678 vm_data = VmData(data.host_name, data.management_ip)
679 self.assert_vm(vm_data, self._flavor)
680
681 # Reboot VM
682 self._reboot_vm(vm_id)
683 ### Delete the VM
684 self._delete_vm(vm_id)
685
686
687 def _get_network_info_request(self):
688 """
689 Returns request object of type RwcalYang.NetworkInfoItem
690 """
691 network = RwcalYang.NetworkInfoItem()
692 network.network_name = 'rift.cal.unittest.network'
693 network.subnet = '192.168.16.0/24'
694 if openstack_info['physical_network']:
695 network.provider_network.physical_network = openstack_info['physical_network']
696 if openstack_info['network_type']:
697 network.provider_network.overlay_type = openstack_info['network_type']
698 if OpenStackTest.SEG_ID:
699 network.provider_network.segmentation_id = OpenStackTest.SEG_ID
700 OpenStackTest.SEG_ID += 1
701 return network
702
703
704 def _create_network(self):
705 """
706 Create a network and verify that network creation is successful
707 """
708 network = self._get_network_info_request()
709
710 ### Create network
711 logger.info("Openstack-CAL-Test: Creating a network with name : %s" %(network.network_name))
712 rc, net_id = self.cal.create_network(self._acct, network)
713 self.assertEqual(rc, RwStatus.SUCCESS)
714
715 ### Verify network is created successfully
716 rc, rs = self.cal.get_network(self._acct, net_id)
717 self.assertEqual(rc, RwStatus.SUCCESS)
718 logger.info("Openstack-CAL-Test: Successfully create Network : %s with id : %s." %(network.network_name, net_id ))
719
720 return net_id
721
722 def _delete_network(self, net_id):
723 """
724 Delete network and verify that delete operation is successful
725 """
726 rc, rs = self.cal.get_network(self._acct, net_id)
727 self.assertEqual(rc, RwStatus.SUCCESS)
728
729 logger.info("Openstack-CAL-Test: Deleting a network with id : %s. " %(net_id))
730 rc = self.cal.delete_network(self._acct, net_id)
731 self.assertEqual(rc, RwStatus.SUCCESS)
732
733 # Verify that network is no longer available via get_network_list API
734 rc, rs = self.cal.get_network_list(self._acct)
735 self.assertEqual(rc, RwStatus.SUCCESS)
736 network_info = [ network for network in rs.networkinfo_list if network.network_id == net_id ]
737 self.assertEqual(len(network_info), 0)
738 logger.info("Openstack-CAL-Test: Successfully deleted Network with id : %s" %(net_id))
739
740
741 @unittest.skip("Skipping test_network_operations")
742 def test_network_operations(self):
743 """
744 Create/Delete Networks
745 """
746 logger.info("Openstack-CAL-Test: Starting Network Operation test")
747
748 ### Create Network
749 net_id = self._create_network()
750
751 ### Delete Network
752 self._delete_network(net_id)
753
754 def _get_port_info_request(self, network_id, vm_id):
755 """
756 Returns an object of type RwcalYang.PortInfoItem
757 """
758 port = RwcalYang.PortInfoItem()
759 port.port_name = 'rift.cal.unittest.port'
760 port.network_id = network_id
761 if vm_id != None:
762 port.vm_id = vm_id
763 return port
764
765 def _create_port(self, net_id, vm_id = None):
766 """
767 Create a port in network with network_id: net_id and verifies that operation is successful
768 """
769 if vm_id != None:
770 logger.info("Openstack-CAL-Test: Creating a port in network with network_id: %s and VM with vm_id: %s" %(net_id, vm_id))
771 else:
772 logger.info("Openstack-CAL-Test: Creating a port in network with network_id: %s" %(net_id))
773
774 ### Create Port
775 port = self._get_port_info_request(net_id, vm_id)
776 rc, port_id = self.cal.create_port(self._acct, port)
777 self.assertEqual(rc, RwStatus.SUCCESS)
778
779 ### Get Port
780 rc, rs = self.cal.get_port(self._acct, port_id)
781 self.assertEqual(rc, RwStatus.SUCCESS)
782 logger.info("Openstack-CAL-Test: Successfully create Port with id : %s. Port State : %s" %(port_id, rs.port_state))
783
784 return port_id
785
786 def _delete_port(self, port_id):
787 """
788 Deletes a port and verifies that operation is successful
789 """
790 rc, rs = self.cal.get_port(self._acct, port_id)
791 self.assertEqual(rc, RwStatus.SUCCESS)
792 logger.info("Openstack-CAL-Test: Deleting Port with id : %s. Port State : %s" %(port_id, rs.port_state))
793
794 ### Delete Port
795 self.cal.delete_port(self._acct, port_id)
796
797 rc, rs = self.cal.get_port_list(self._acct)
798 self.assertEqual(rc, RwStatus.SUCCESS)
799 port_list = [ port for port in rs.portinfo_list if port.port_id == port_id ]
800 self.assertEqual(len(port_list), 0)
801 logger.info("Openstack-CAL-Test: Successfully Deleted Port with id : %s" %(port_id))
802
803 def _monitor_port(self, port_id, expected_state):
804 """
805 Monitor the port state until it reaches expected_state
806 """
807 for i in range(50):
808 rc, rs = self.cal.get_port(self._acct, port_id)
809 self.assertEqual(rc, RwStatus.SUCCESS)
810 logger.info("Openstack-CAL-Test: Port with id : %s. Port State : %s" %(port_id, rs.port_state))
811 if rs.port_state == expected_state:
812 break
813 rc, rs = self.cal.get_port(self._acct, port_id)
814 self.assertEqual(rc, RwStatus.SUCCESS)
815 self.assertEqual(rs.port_state, expected_state)
816 logger.info("Openstack-CAL-Test: Port with port_id : %s reached expected state : %s" %(port_id, rs.port_state))
817
818 @unittest.skip("Skipping test_port_operations_with_vm")
819 def test_port_operations_with_vm(self):
820 """
821 Create/Delete Ports in a network and associate it with a VM
822 """
823 logger.info("Openstack-CAL-Test: Starting Port Operation test with VM")
824
825 ### First create a network
826 net_id = self._create_network()
827
828 ### Create a VM
829 data, vm_id = self._create_vm(self._flavor, self._image)
830
831 ### Now create Port which connects VM to Network
832 port_id = self._create_port(net_id, vm_id)
833
834 ### Verify that port goes to active state
835 self._monitor_port(port_id, 'ACTIVE')
836
837 ### Delete VM
838 self._delete_vm(vm_id)
839
840 ### Delete Port
841 self._delete_port(port_id)
842
843 ### Delete the network
844 self._delete_network(net_id)
845
846 @unittest.skip("Skipping test_create_vm_with_port")
847 def test_create_vm_with_port(self):
848 """
849 Create VM and add ports to it during boot time.
850 """
851 logger.info("Openstack-CAL-Test: Starting Create VM with port test")
852
853 ### First create a network
854 net_id = self._create_network()
855
856 ### Now create Port which connects VM to Network
857 port_id = self._create_port(net_id)
858
859 ### Create a VM
860 data, vm_id = self._create_vm(self._flavor, self._image, [port_id])
861
862 ### Verify that port goes to active state
863 self._monitor_port(port_id, 'ACTIVE')
864
865 ### Delete VM
866 self._delete_vm(vm_id)
867
868 ### Delete Port
869 self._delete_port(port_id)
870
871 ### Delete the network
872 self._delete_network(net_id)
873
874 @unittest.skip("Skipping test_get_vdu_list")
875 def test_get_vdu_list(self):
876 """
877 Test the get_vdu_list API
878 """
879 logger.info("Openstack-CAL-Test: Test Get VDU List APIs")
880 rc, rsp = self.cal.get_vdu_list(self._acct)
881 self.assertEqual(rc, RwStatus.SUCCESS)
882 logger.info("Openstack-CAL-Test: Received %d VDUs" %(len(rsp.vdu_info_list)))
883 for vdu in rsp.vdu_info_list:
884 rc, vdu2 = self.cal.get_vdu(self._acct, vdu.vdu_id)
885 self.assertEqual(vdu2.vdu_id, vdu.vdu_id)
886
887
888 @unittest.skip("Skipping test_get_virtual_link_list")
889 def test_get_virtual_link_list(self):
890 """
891 Test the get_virtual_link_list API
892 """
893 logger.info("Openstack-CAL-Test: Test Get virtual_link List APIs")
894 rc, rsp = self.cal.get_virtual_link_list(self._acct)
895 self.assertEqual(rc, RwStatus.SUCCESS)
896 logger.info("Openstack-CAL-Test: Received %d virtual_links" %(len(rsp.virtual_link_info_list)))
897 for virtual_link in rsp.virtual_link_info_list:
898 rc, virtual_link2 = self.cal.get_virtual_link(self._acct, virtual_link.virtual_link_id)
899 self.assertEqual(virtual_link2.virtual_link_id, virtual_link.virtual_link_id)
900
901 def _get_virtual_link_request_info(self):
902 """
903 Returns object of type RwcalYang.VirtualLinkReqParams
904 """
905 vlink = RwcalYang.VirtualLinkReqParams()
906 vlink.name = 'rift.cal.virtual_link'
907 vlink.subnet = '192.168.1.0/24'
908 if openstack_info['physical_network']:
909 vlink.provider_network.physical_network = openstack_info['physical_network']
910 if openstack_info['network_type']:
911 vlink.provider_network.overlay_type = openstack_info['network_type'].upper()
912 if OpenStackTest.SEG_ID:
913 vlink.provider_network.segmentation_id = OpenStackTest.SEG_ID
914 OpenStackTest.SEG_ID += 1
915 return vlink
916
917 def _get_vdu_request_info(self, virtual_link_id):
918 """
919 Returns object of type RwcalYang.VDUInitParams
920 """
921 vdu = RwcalYang.VDUInitParams()
922 vdu.name = "cal.vdu"
923 vdu.node_id = OpenStackTest.NodeID
924 vdu.image_id = self._image.id
925 vdu.flavor_id = self._flavor.id
926 vdu.vdu_init.userdata = ''
927 vdu.allocate_public_address = True
928 c1 = vdu.connection_points.add()
929 c1.name = "c_point1"
930 c1.virtual_link_id = virtual_link_id
931 c1.type_yang = 'VIRTIO'
932 return vdu
933
934 def _get_vdu_modify_request_info(self, vdu_id, virtual_link_id):
935 """
936 Returns object of type RwcalYang.VDUModifyParams
937 """
938 vdu = RwcalYang.VDUModifyParams()
939 vdu.vdu_id = vdu_id
940 c1 = vdu.connection_points_add.add()
941 c1.name = "c_modify1"
942 c1.virtual_link_id = virtual_link_id
943
944 return vdu
945
946 #@unittest.skip("Skipping test_create_delete_virtual_link_and_vdu")
947 def test_create_delete_virtual_link_and_vdu(self):
948 """
949 Test to create VDU
950 """
951 logger.info("Openstack-CAL-Test: Test Create Virtual Link API")
952 vlink_req = self._get_virtual_link_request_info()
953
954 rc, rsp = self.cal.create_virtual_link(self._acct, vlink_req)
955 self.assertEqual(rc.status, RwStatus.SUCCESS)
956 logger.info("Openstack-CAL-Test: Created virtual_link with Id: %s" %rsp)
957 vlink_id = rsp
958
959 #Check if virtual_link create is successful
960 rc, rsp = self.cal.get_virtual_link(self._acct, rsp)
961 self.assertEqual(rc, RwStatus.SUCCESS)
962 self.assertEqual(rsp.virtual_link_id, vlink_id)
963
964 # Now create VDU
965 vdu_req = self._get_vdu_request_info(vlink_id)
966 logger.info("Openstack-CAL-Test: Test Create VDU API")
967
968 rc, rsp = self.cal.create_vdu(self._acct, vdu_req)
969 self.assertEqual(rc.status, RwStatus.SUCCESS)
970 logger.info("Openstack-CAL-Test: Created vdu with Id: %s" %rsp)
971
972 vdu_id = rsp
973
974 ## Check if VDU create is successful
975 rc, rsp = self.cal.get_vdu(self._acct, rsp)
976 self.assertEqual(rsp.vdu_id, vdu_id)
977
978 ### Wait until vdu_state is active
979 for i in range(50):
980 rc, rs = self.cal.get_vdu(self._acct, vdu_id)
981 self.assertEqual(rc, RwStatus.SUCCESS)
982 logger.info("Openstack-CAL-Test: VDU with id : %s. Reached State : %s" %(vdu_id, rs.state))
983 if rs.state == 'active':
984 break
985 rc, rs = self.cal.get_vdu(self._acct, vdu_id)
986 self.assertEqual(rc, RwStatus.SUCCESS)
987 self.assertEqual(rs.state, 'active')
988 logger.info("Openstack-CAL-Test: VDU with id : %s reached expected state : %s" %(vdu_id, rs.state))
989 logger.info("Openstack-CAL-Test: VDUInfo: %s" %(rs))
990
991 vlink_req = self._get_virtual_link_request_info()
992
993 ### Create another virtual_link
994 rc, rsp = self.cal.create_virtual_link(self._acct, vlink_req)
995 self.assertEqual(rc.status, RwStatus.SUCCESS)
996 logger.info("Openstack-CAL-Test: Created virtual_link with Id: %s" %rsp)
997 vlink_id2= rsp
998
999 ### Now exercise the modify_vdu_api
1000 vdu_modify = self._get_vdu_modify_request_info(vdu_id, vlink_id2)
1001 rc = self.cal.modify_vdu(self._acct, vdu_modify)
1002 self.assertEqual(rc, RwStatus.SUCCESS)
1003 logger.info("Openstack-CAL-Test: Modified vdu with Id: %s" %vdu_id)
1004
1005 ### Lets delete the VDU
1006 self.cal.delete_vdu(self._acct, vdu_id)
1007
1008 ### Lets delete the Virtual Link
1009 self.cal.delete_virtual_link(self._acct, vlink_id)
1010
1011 ### Lets delete the Virtual Link-2
1012 self.cal.delete_virtual_link(self._acct, vlink_id2)
1013
1014 time.sleep(5)
1015 ### Verify that VDU and virtual link are successfully deleted
1016 rc, rsp = self.cal.get_vdu_list(self._acct)
1017 self.assertEqual(rc, RwStatus.SUCCESS)
1018 for vdu in rsp.vdu_info_list:
1019 self.assertNotEqual(vdu.vdu_id, vdu_id)
1020
1021 rc, rsp = self.cal.get_virtual_link_list(self._acct)
1022 self.assertEqual(rc, RwStatus.SUCCESS)
1023
1024 for virtual_link in rsp.virtual_link_info_list:
1025 self.assertNotEqual(virtual_link.virtual_link_id, vlink_id)
1026
1027 logger.info("Openstack-CAL-Test: VDU/Virtual Link create-delete test successfully completed")
1028
1029 class VmData(object):
1030 """A convenience class that provides all the stats and EPA Attributes
1031 from the VM provided
1032 """
1033 def __init__(self, host, mgmt_ip):
1034 """
1035 Args:
1036 host (str): host name.
1037 mgmt_ip (str): The IP of the newly created VM.
1038 """
1039 # Sleep for 20s to ensure the VM is UP and ready to run commands
1040 time.sleep(20)
1041 logger.info("Connecting to host: {} and IP: {}".format(host, mgmt_ip))
1042 self.client = paramiko.SSHClient()
1043 self.client.set_missing_host_key_policy(paramiko.WarningPolicy())
1044 self.client.connect(host)
1045 self.ip = mgmt_ip
1046
1047 # Get all data from the newly created VM.
1048 self._data = self._get_data()
1049 self._page_size = self._exec_and_clean("getconf PAGE_SIZE")
1050 self._disk_space = self._exec_and_clean(
1051 "df -kh --output=size /",
1052 line_no=1)
1053 self._pci_data = self._exec('lspci -m | grep "10-Gigabit"')
1054
1055 def _get_data(self,):
1056 """Runs the command and store the output in a python dict.
1057
1058 Returns:
1059 dict: Containing all key => value pairs.
1060 """
1061 content = {}
1062 cmds = ["lscpu", 'less /proc/meminfo']
1063 for cmd in cmds:
1064 ssh_out = self._exec(cmd)
1065 content.update(self._convert_to_dict(ssh_out))
1066 return content
1067
1068 def _exec_and_clean(self, cmd, line_no=0):
1069 """A convenience method to run a command and extract the specified line
1070 number.
1071
1072 Args:
1073 cmd (str): Command to execute
1074 line_no (int, optional): Default to 0, extracts the first line.
1075
1076 Returns:
1077 str: line_no of the output of the command.
1078 """
1079 output = self._exec(cmd)[line_no]
1080 output = ' '.join(output.split())
1081 return output.strip()
1082
1083 def _exec(self, cmd):
1084 """Thin wrapper that runs the command and returns the stdout data
1085
1086 Args:
1087 cmd (str): Command to execute.
1088
1089 Returns:
1090 list: Contains the command output.
1091 """
1092 _, ssh_out, _ = self.client.exec_command(
1093 "/usr/rift/bin/ssh_root {} {}".format(self.ip,
1094 cmd))
1095 return ssh_out.readlines()
1096
1097 def _convert_to_dict(self, content):
1098 """convenience method that cleans and stores the line into dict.
1099 data is split based on ":" or " ".
1100
1101 Args:
1102 content (list): A list containing the stdout.
1103
1104 Returns:
1105 dict: containing stat attribute => value.
1106 """
1107 flattened = {}
1108 for line in content:
1109 line = ' '.join(line.split())
1110 if ":" in line:
1111 key, value = line.split(":")
1112 else:
1113 key, value = line.split(" ")
1114 key, value = key.strip(), value.strip()
1115 flattened[key] = value
1116 return flattened
1117
1118 @property
1119 def disk(self):
1120 disk = self._disk_space.replace("G", "")
1121 return int(disk)
1122
1123 @property
1124 def numa_node_count(self):
1125 numa_cores = self._data['NUMA node(s)']
1126 numa_cores = int(numa_cores)
1127 return numa_cores
1128
1129 @property
1130 def vcpus(self):
1131 cores = int(self._data['CPU(s)'])
1132 return cores
1133
1134 @property
1135 def cpu_threads(self):
1136 threads = int(self._data['Thread(s) per core'])
1137 return threads
1138
1139 @property
1140 def memory(self):
1141 memory = self._data['MemTotal']
1142 memory = int(memory.replace("kB", ""))/1000/1000
1143 return int(memory)
1144
1145 @property
1146 def memory_page_size(self):
1147 return self._page_size
1148
1149 @property
1150 def pci_passthrough_device_list(self):
1151 return self._pci_data
1152
1153
1154 if __name__ == "__main__":
1155 logging.basicConfig(level=logging.DEBUG)
1156 unittest.main()