3 # Copyright 2016 RIFT.IO Inc
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
24 import novaclient
.exceptions
as nova_exception
28 from keystoneclient
import v3
as ksclient
30 from gi
.repository
import RwcalYang
31 from gi
.repository
.RwTypes
import RwStatus
32 from rift
.rwcal
.openstack
.openstack_drv
import KeystoneDriver
, NovaDriver
34 logger
= logging
.getLogger('rwcal-openstack')
37 # Important information about openstack installation. This needs to be manually verified
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
53 def get_cal_account():
55 Creates an object for class RwcalYang.CloudAccount()
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']
69 Loads rw.cal plugin via libpeas
71 plugin
= rw_peas
.PeasPlugin('rwcal_openstack', 'RwCal-1.0')
72 engine
, info
, extension
= plugin()
74 # Get the RwLogger context
75 rwloggerctx
= rwlogger
.RwLog
.Ctx
.new("Cal-Log")
77 cal
= plugin
.get_interface("Cloud")
79 rc
= cal
.init(rwloggerctx
)
80 assert rc
== RwStatus
.SUCCESS
82 logger
.error("ERROR:Cal plugin instantiation failed. Aborting tests")
84 logger
.info("Openstack Cal plugin successfully instantiated")
88 class OpenStackTest(unittest
.TestCase
):
89 NodeID
= "123456789012345" # Some random number to test VM tagging
90 MemoryPageSize
= "LARGE"
91 CpuPolicy
= "DEDICATED"
92 CpuThreadPolicy
= "SEPARATE"
96 PCIPassThroughAlias
= "PCI_10G_ALIAS"
97 SEG_ID
= openstack_info
['segmentation_id']
102 - It is assumed that openstack install has a flavor and image precreated.
103 - Flavor_name: x1.xlarge
104 - Image_name : rwimage
106 If these resources are not then this test will fail.
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")
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
)
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]
121 rc
, rs
= self
.cal
.get_image_list(self
._acct
)
122 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
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]
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
)
136 logger
.info("Openstack-CAL-Test: tearDown")
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()
146 @unittest.skip("Skipping test_list_flavors")
147 def test_list_flavor(self
):
149 List existing flavors from openstack installation
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)
160 @unittest.skip("Skipping test_list_images")
161 def test_list_images(self
):
163 List existing images from openstack installation
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)
174 @unittest.skip("Skipping test_list_vms")
175 def test_list_vms(self
):
177 List existing VMs from openstack installation
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
)
187 @unittest.skip("Skipping test_list_networks")
188 def test_list_networks(self
):
190 List existing Network from openstack installation
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
)
200 @unittest.skip("Skipping test_list_ports")
201 def test_list_ports(self
):
203 List existing Ports from openstack installation
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
)
214 def _get_image_info_request(self
):
216 Returns request object of type RwcalYang.ImageInfoItem()
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
._md
5(img
.location
)
226 def _get_image_info(self
, img_id
):
228 Checks the image status until it becomes active or timeout occurs (100sec)
229 Returns the image_info dictionary
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':
240 time
.sleep(2) # Sleep for a second
243 @unittest.skip("Skipping test_create_delete_image")
244 def test_create_delete_image(self
):
246 Create/Query/Delete a new image in openstack installation
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))
264 def _get_flavor_info_request(self
):
266 Returns request object of type RwcalYang.FlavorInfoItem()
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()
281 vcpu
= node
.vcpu
.add()
283 vcpu
= node
.vcpu
.add()
286 vcpu
= node
.vcpu
.add()
288 vcpu
= node
.vcpu
.add()
290 node
.memory_mb
= 8196
291 dev
= flavor
.guest_epa
.pcie_device
.add()
292 dev
.device_id
= OpenStackTest
.PCIPassThroughAlias
296 @unittest.skip("Skipping test_create_delete_flavor")
297 def test_create_delete_flavor(self
):
299 Create/Query/Delete a new flavor in openstack installation
301 logger
.info("Openstack-CAL-Test: Starting Image create/delete test")
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' ]
308 rc
= self
.cal
.delete_flavor(self
._acct
, flavor_list
[0].id)
309 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
311 flavor
= self
._get
_flavor
_info
_request
()
312 rc
, flavor_id
= self
.cal
.create_flavor(self
._acct
, flavor
)
313 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
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
)
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))
339 def _get_vm_info_request(self
, flavor_id
, image_id
):
341 Returns request object of type RwcalYang.VMInfoItem
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
351 def _check_vm_state(self
, vm_id
, expected_state
):
353 Wait until VM reaches particular state (expected_state).
355 # Wait while VM goes to required state
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
:
366 rc
, rs
= self
.cal
.get_vm(self
._acct
, vm_id
)
367 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
368 self
.assertEqual(rs
.state
, expected_state
)
370 def _create_vm(self
, flavor
, image
, port_list
= None):
372 Create VM and perform validity checks
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)
378 for port_id
in port_list
:
379 port
= vm
.port_list
.add()
380 port
.port_id
= port_id
382 rc
, vm_id
= self
.cal
.create_vm(self
._acct
, vm
)
383 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
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
))
390 ### Ensure the VM state is active
391 self
._check
_vm
_state
(vm_id
, 'ACTIVE')
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))
401 def _delete_vm(self
, vm_id
):
403 Delete VM and perform validity checks
405 rc
, rs
= self
.cal
.get_vm(self
._acct
, vm_id
)
406 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
408 logger
.info("Openstack-CAL-Test: Initiating VM Delete operation on VM vm_id : %s. Current VM state : %s " %(vm_id
, rs
.state
))
410 rc
= self
.cal
.delete_vm(self
._acct
, vm_id
)
411 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
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
]
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))
427 def _stop_vm(self
, vm_id
):
429 Stop VM and perform validity checks
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')
440 def _start_vm(self
, vm_id
):
442 Starts VM and performs validity checks
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
)
450 ### Ensure that VM state is ACTIVE
451 self
._check
_vm
_state
(vm_id
, 'ACTIVE')
454 def _reboot_vm(self
, vm_id
):
456 Reboot VM and perform validity checks
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
)
464 ### Ensure that VM state is ACTIVE
465 self
._check
_vm
_state
(vm_id
, 'ACTIVE')
467 def assert_vm(self
, vm_data
, flavor
):
468 """Verify the newly created VM for attributes specified in the flavor.
471 vm_data (VmData): Instance of the newly created VM
472 flavor (FlavorInfoItem): Config flavor.
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"]
482 if field
not in vm_config
:
485 vm_value
= getattr(vm_data
, field
)
486 config_value
= getattr(vm_config
, field
)
488 if field
== "memory_page_size":
489 config_value
= page_lookup
[config_value
]
491 if field
== "memory":
492 config_value
= int(config_value
/1000)
494 if field
== "pci_passthrough_device_list":
495 config_value
= len(config_value
)
496 vm_value
= len(vm_value
)
498 self
.assertEqual(vm_value
, config_value
)
500 @unittest.skip("Skipping test_vm_epa_attributes")
501 def test_vm_epa_attributes(self
):
503 Primary goal: To create a VM with the specified EPA Attributes
504 Secondary goal: To verify flavor creation/delete
507 logger
.info("Openstack-CAL-Test: Starting VM(EPA) create/delete test")
508 flavor
= self
._get
_flavor
_info
_request
()
510 rc
, flavor_id
= self
.cal
.do_create_flavor(self
._acct
, flavor
)
511 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
512 flavor
.id = flavor_id
514 data
, vm_id
= self
._create
_vm
(flavor
, self
._image
)
516 vm_data
= VmData(data
.host_name
, data
.management_ip
)
517 self
.assert_vm(vm_data
, flavor
)
519 self
._delete
_vm
(vm_id
)
521 rc
= self
.cal
.do_delete_flavor(self
._acct
, flavor_id
)
522 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
524 @unittest.skip("Skipping test_expiry_token")
525 def test_expiry_token(self
):
527 Primary goal: To verify if we are refreshing the expired tokens.
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
()
538 auth_ref
= client
.auth_ref
539 token
= auth_ref
['auth_token']
541 # Verify if the newly acquired token works.
542 nova
= NovaDriver(drv
)
543 flavors
= nova
.flavor_list()
544 self
.assertTrue(len(flavors
) > 1)
546 # Invalidate the token
547 token_manger
= ksclient
.tokens
.TokenManager(client
)
548 token_manger
.revoke_token(token
)
554 flavors
= nova
.flavor_list()
556 except nova_exception
.AuthorizationFailure
:
559 self
.assertTrue(unauth_exp
)
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
566 flavors
= nova
.flavor_list()
567 self
.assertTrue(len(flavors
) > 1)
569 @unittest.skip("Skipping test_vm_operations")
570 def test_vm_operations(self
):
572 Primary goal: Create/Query/Delete VM in openstack installation.
573 Secondary goal: VM pause/resume operations on VM.
576 logger
.info("Openstack-CAL-Test: Starting VM Operations test")
579 data
, vm_id
= self
._create
_vm
(self
._flavor
, self
._image
)
584 self
._start
_vm
(vm_id
)
586 vm_data
= VmData(data
.host_name
, data
.management_ip
)
587 self
.assert_vm(vm_data
, self
._flavor
)
590 self
._reboot
_vm
(vm_id
)
592 self
._delete
_vm
(vm_id
)
595 def _get_network_info_request(self
):
597 Returns request object of type RwcalYang.NetworkInfoItem
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
612 def _create_network(self
):
614 Create a network and verify that network creation is successful
616 network
= self
._get
_network
_info
_request
()
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
)
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
))
630 def _delete_network(self
, net_id
):
632 Delete network and verify that delete operation is successful
634 rc
, rs
= self
.cal
.get_network(self
._acct
, net_id
)
635 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
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
)
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))
649 @unittest.skip("Skipping test_network_operations")
650 def test_network_operations(self
):
652 Create/Delete Networks
654 logger
.info("Openstack-CAL-Test: Starting Network Operation test")
657 net_id
= self
._create
_network
()
660 self
._delete
_network
(net_id
)
662 def _get_port_info_request(self
, network_id
, vm_id
):
664 Returns an object of type RwcalYang.PortInfoItem
666 port
= RwcalYang
.PortInfoItem()
667 port
.port_name
= 'rift.cal.unittest.port'
668 port
.network_id
= network_id
673 def _create_port(self
, net_id
, vm_id
= None):
675 Create a port in network with network_id: net_id and verifies that operation is successful
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
))
680 logger
.info("Openstack-CAL-Test: Creating a port in network with network_id: %s" %(net_id))
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
)
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
))
694 def _delete_port(self
, port_id
):
696 Deletes a port and verifies that operation is successful
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
))
703 self
.cal
.delete_port(self
._acct
, port_id
)
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))
711 def _monitor_port(self
, port_id
, expected_state
):
713 Monitor the port state until it reaches expected_state
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
:
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
))
726 @unittest.skip("Skipping test_port_operations_with_vm")
727 def test_port_operations_with_vm(self
):
729 Create/Delete Ports in a network and associate it with a VM
731 logger
.info("Openstack-CAL-Test: Starting Port Operation test with VM")
733 ### First create a network
734 net_id
= self
._create
_network
()
737 data
, vm_id
= self
._create
_vm
(self
._flavor
, self
._image
)
739 ### Now create Port which connects VM to Network
740 port_id
= self
._create
_port
(net_id
, vm_id
)
742 ### Verify that port goes to active state
743 self
._monitor
_port
(port_id
, 'ACTIVE')
746 self
._delete
_vm
(vm_id
)
749 self
._delete
_port
(port_id
)
751 ### Delete the network
752 self
._delete
_network
(net_id
)
754 @unittest.skip("Skipping test_create_vm_with_port")
755 def test_create_vm_with_port(self
):
757 Create VM and add ports to it during boot time.
759 logger
.info("Openstack-CAL-Test: Starting Create VM with port test")
761 ### First create a network
762 net_id
= self
._create
_network
()
764 ### Now create Port which connects VM to Network
765 port_id
= self
._create
_port
(net_id
)
768 data
, vm_id
= self
._create
_vm
(self
._flavor
, self
._image
, [port_id
])
770 ### Verify that port goes to active state
771 self
._monitor
_port
(port_id
, 'ACTIVE')
774 self
._delete
_vm
(vm_id
)
777 self
._delete
_port
(port_id
)
779 ### Delete the network
780 self
._delete
_network
(net_id
)
782 @unittest.skip("Skipping test_get_vdu_list")
783 def test_get_vdu_list(self
):
785 Test the get_vdu_list API
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
)
796 @unittest.skip("Skipping test_get_virtual_link_list")
797 def test_get_virtual_link_list(self
):
799 Test the get_virtual_link_list API
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
)
809 def _get_virtual_link_request_info(self
):
811 Returns object of type RwcalYang.VirtualLinkReqParams
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
825 def _get_vdu_request_info(self
, virtual_link_id
):
827 Returns object of type RwcalYang.VDUInitParams
829 vdu
= RwcalYang
.VDUInitParams()
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()
838 c1
.virtual_link_id
= virtual_link_id
839 c1
.type_yang
= 'VIRTIO'
842 def _get_vdu_modify_request_info(self
, vdu_id
, virtual_link_id
):
844 Returns object of type RwcalYang.VDUModifyParams
846 vdu
= RwcalYang
.VDUModifyParams()
848 c1
= vdu
.connection_points_add
.add()
849 c1
.name
= "c_modify1"
850 c1
.virtual_link_id
= virtual_link_id
854 #@unittest.skip("Skipping test_create_delete_virtual_link_and_vdu")
855 def test_create_delete_virtual_link_and_vdu(self
):
859 logger
.info("Openstack-CAL-Test: Test Create Virtual Link API")
860 vlink_req
= self
._get
_virtual
_link
_request
_info
()
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
)
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
)
873 vdu_req
= self
._get
_vdu
_request
_info
(vlink_id
)
874 logger
.info("Openstack-CAL-Test: Test Create VDU API")
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
)
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
)
886 ### Wait until vdu_state is active
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':
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))
899 vlink_req
= self
._get
_virtual
_link
_request
_info
()
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
)
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
)
913 ### Lets delete the VDU
914 self
.cal
.delete_vdu(self
._acct
, vdu_id
)
916 ### Lets delete the Virtual Link
917 self
.cal
.delete_virtual_link(self
._acct
, vlink_id
)
919 ### Lets delete the Virtual Link-2
920 self
.cal
.delete_virtual_link(self
._acct
, vlink_id2
)
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
)
929 rc
, rsp
= self
.cal
.get_virtual_link_list(self
._acct
)
930 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
932 for virtual_link
in rsp
.virtual_link_info_list
:
933 self
.assertNotEqual(virtual_link
.virtual_link_id
, vlink_id
)
935 logger
.info("Openstack-CAL-Test: VDU/Virtual Link create-delete test successfully completed")
937 class VmData(object):
938 """A convenience class that provides all the stats and EPA Attributes
941 def __init__(self
, host
, mgmt_ip
):
944 host (str): host name.
945 mgmt_ip (str): The IP of the newly created VM.
947 # Sleep for 20s to ensure the VM is UP and ready to run commands
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
)
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 /",
961 self
._pci
_data
= self
._exec
('lspci -m | grep "10-Gigabit"')
963 def _get_data(self
,):
964 """Runs the command and store the output in a python dict.
967 dict: Containing all key => value pairs.
970 cmds
= ["lscpu", 'less /proc/meminfo']
972 ssh_out
= self
._exec
(cmd
)
973 content
.update(self
._convert
_to
_dict
(ssh_out
))
976 def _exec_and_clean(self
, cmd
, line_no
=0):
977 """A convenience method to run a command and extract the specified line
981 cmd (str): Command to execute
982 line_no (int, optional): Default to 0, extracts the first line.
985 str: line_no of the output of the command.
987 output
= self
._exec
(cmd
)[line_no
]
988 output
= ' '.join(output
.split())
989 return output
.strip()
991 def _exec(self
, cmd
):
992 """Thin wrapper that runs the command and returns the stdout data
995 cmd (str): Command to execute.
998 list: Contains the command output.
1000 _
, ssh_out
, _
= self
.client
.exec_command(
1001 "/usr/rift/bin/ssh_root {} {}".format(self
.ip
,
1003 return ssh_out
.readlines()
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 " ".
1010 content (list): A list containing the stdout.
1013 dict: containing stat attribute => value.
1016 for line
in content
:
1017 line
= ' '.join(line
.split())
1019 key
, value
= line
.split(":")
1021 key
, value
= line
.split(" ")
1022 key
, value
= key
.strip(), value
.strip()
1023 flattened
[key
] = value
1028 disk
= self
._disk
_space
.replace("G", "")
1032 def numa_node_count(self
):
1033 numa_cores
= self
._data
['NUMA node(s)']
1034 numa_cores
= int(numa_cores
)
1039 cores
= int(self
._data
['CPU(s)'])
1043 def cpu_threads(self
):
1044 threads
= int(self
._data
['Thread(s) per core'])
1049 memory
= self
._data
['MemTotal']
1050 memory
= int(memory
.replace("kB", ""))/1000/1000
1054 def memory_page_size(self
):
1055 return self
._page
_size
1058 def pci_passthrough_device_list(self
):
1059 return self
._pci
_data
1062 if __name__
== "__main__":
1063 logging
.basicConfig(level
=logging
.DEBUG
)