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