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.
23 import novaclient
.exceptions
as nova_exception
27 from keystoneclient
import v3
as ksclient
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
33 logger
= logging
.getLogger('rwcal-openstack')
36 # Important information about openstack installation. This needs to be manually verified
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'
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'
67 def get_cal_account():
69 Creates an object for class RwcalYang.CloudAccount()
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']
85 Loads rw.cal plugin via libpeas
87 plugin
= rw_peas
.PeasPlugin('rwcal_openstack', 'RwCal-1.0')
88 engine
, info
, extension
= plugin()
90 # Get the RwLogger context
91 rwloggerctx
= rwlogger
.RwLog
.Ctx
.new("Cal-Log")
93 cal
= plugin
.get_interface("Cloud")
95 rc
= cal
.init(rwloggerctx
)
96 assert rc
== RwStatus
.SUCCESS
98 logger
.error("ERROR:Cal plugin instantiation failed. Aborting tests")
100 logger
.info("Openstack Cal plugin successfully instantiated")
104 class OpenStackTest(unittest
.TestCase
):
105 NodeID
= "123456789012345" # Some random number to test VM tagging
106 MemoryPageSize
= "LARGE"
107 CpuPolicy
= "DEDICATED"
108 CpuThreadPolicy
= "SEPARATE"
111 HostTrust
= "trusted"
112 PCIPassThroughAlias
= "PCI_10G_ALIAS"
113 SEG_ID
= openstack_info
['segmentation_id']
118 - It is assumed that openstack install has a flavor and image precreated.
119 - Flavor_name: x1.xlarge
120 - Image_name : rwimage
122 If these resources are not then this test will fail.
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")
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
)
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]
137 rc
, rs
= self
.cal
.get_image_list(self
._acct
)
138 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
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]
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
)
152 logger
.info("Openstack-CAL-Test: tearDown")
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()
162 @unittest.skip("Skipping test_list_flavors")
163 def test_list_flavor(self
):
165 List existing flavors from openstack installation
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)
176 @unittest.skip("Skipping test_list_images")
177 def test_list_images(self
):
179 List existing images from openstack installation
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)
190 @unittest.skip("Skipping test_list_vms")
191 def test_list_vms(self
):
193 List existing VMs from openstack installation
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
)
203 @unittest.skip("Skipping test_list_networks")
204 def test_list_networks(self
):
206 List existing Network from openstack installation
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
)
216 @unittest.skip("Skipping test_list_ports")
217 def test_list_ports(self
):
219 List existing Ports from openstack installation
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
)
230 def _get_image_info_request(self
):
232 Returns request object of type RwcalYang.ImageInfoItem()
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
._md
5(img
.location
)
242 def _get_image_info(self
, img_id
):
244 Checks the image status until it becomes active or timeout occurs (100sec)
245 Returns the image_info dictionary
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':
256 time
.sleep(2) # Sleep for a second
259 @unittest.skip("Skipping test_create_delete_image")
260 def test_create_delete_image(self
):
262 Create/Query/Delete a new image in openstack installation
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))
280 def _get_flavor_info_request(self
):
282 Returns request object of type RwcalYang.FlavorInfoItem()
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()
297 vcpu
= node
.vcpu
.add()
299 vcpu
= node
.vcpu
.add()
302 vcpu
= node
.vcpu
.add()
304 vcpu
= node
.vcpu
.add()
306 node
.memory_mb
= 8196
307 dev
= flavor
.guest_epa
.pcie_device
.add()
308 dev
.device_id
= OpenStackTest
.PCIPassThroughAlias
312 @unittest.skip("Skipping test_create_delete_flavor")
313 def test_create_delete_flavor(self
):
315 Create/Query/Delete a new flavor in openstack installation
317 logger
.info("Openstack-CAL-Test: Starting Image create/delete test")
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' ]
324 rc
= self
.cal
.delete_flavor(self
._acct
, flavor_list
[0].id)
325 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
327 flavor
= self
._get
_flavor
_info
_request
()
328 rc
, flavor_id
= self
.cal
.create_flavor(self
._acct
, flavor
)
329 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
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
)
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))
355 def _get_vm_info_request(self
, flavor_id
, image_id
):
357 Returns request object of type RwcalYang.VMInfoItem
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
367 def _check_vm_state(self
, vm_id
, expected_state
):
369 Wait until VM reaches particular state (expected_state).
371 # Wait while VM goes to required state
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
:
382 rc
, rs
= self
.cal
.get_vm(self
._acct
, vm_id
)
383 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
384 self
.assertEqual(rs
.state
, expected_state
)
386 def _create_vm(self
, flavor
, image
, port_list
= None):
388 Create VM and perform validity checks
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)
394 for port_id
in port_list
:
395 port
= vm
.port_list
.add()
396 port
.port_id
= port_id
398 rc
, vm_id
= self
.cal
.create_vm(self
._acct
, vm
)
399 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
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
))
406 ### Ensure the VM state is active
407 self
._check
_vm
_state
(vm_id
, 'ACTIVE')
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))
417 def _delete_vm(self
, vm_id
):
419 Delete VM and perform validity checks
421 rc
, rs
= self
.cal
.get_vm(self
._acct
, vm_id
)
422 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
424 logger
.info("Openstack-CAL-Test: Initiating VM Delete operation on VM vm_id : %s. Current VM state : %s " %(vm_id
, rs
.state
))
426 rc
= self
.cal
.delete_vm(self
._acct
, vm_id
)
427 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
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
]
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))
443 def _stop_vm(self
, vm_id
):
445 Stop VM and perform validity checks
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')
456 def _start_vm(self
, vm_id
):
458 Starts VM and performs validity checks
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
)
466 ### Ensure that VM state is ACTIVE
467 self
._check
_vm
_state
(vm_id
, 'ACTIVE')
470 def _reboot_vm(self
, vm_id
):
472 Reboot VM and perform validity checks
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
)
480 ### Ensure that VM state is ACTIVE
481 self
._check
_vm
_state
(vm_id
, 'ACTIVE')
483 def assert_vm(self
, vm_data
, flavor
):
484 """Verify the newly created VM for attributes specified in the flavor.
487 vm_data (VmData): Instance of the newly created VM
488 flavor (FlavorInfoItem): Config flavor.
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"]
498 if field
not in vm_config
:
501 vm_value
= getattr(vm_data
, field
)
502 config_value
= getattr(vm_config
, field
)
504 if field
== "memory_page_size":
505 config_value
= page_lookup
[config_value
]
507 if field
== "memory":
508 config_value
= int(config_value
/1000)
510 if field
== "pci_passthrough_device_list":
511 config_value
= len(config_value
)
512 vm_value
= len(vm_value
)
514 self
.assertEqual(vm_value
, config_value
)
516 @unittest.skip("Skipping test_vm_epa_attributes")
517 def test_vm_epa_attributes(self
):
519 Primary goal: To create a VM with the specified EPA Attributes
520 Secondary goal: To verify flavor creation/delete
523 logger
.info("Openstack-CAL-Test: Starting VM(EPA) create/delete test")
524 flavor
= self
._get
_flavor
_info
_request
()
526 rc
, flavor_id
= self
.cal
.do_create_flavor(self
._acct
, flavor
)
527 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
528 flavor
.id = flavor_id
530 data
, vm_id
= self
._create
_vm
(flavor
, self
._image
)
532 vm_data
= VmData(data
.host_name
, data
.management_ip
)
533 self
.assert_vm(vm_data
, flavor
)
535 self
._delete
_vm
(vm_id
)
537 rc
= self
.cal
.do_delete_flavor(self
._acct
, flavor_id
)
538 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
540 @unittest.skip("Skipping test_expiry_token")
541 def test_expiry_token(self
):
543 Primary goal: To verify if we are refreshing the expired tokens.
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'],
551 openstack_info
['project_name'])
552 # Get hold of the client instance need for Token Manager
553 client
= drv
._get
_keystone
_connection
()
555 auth_ref
= client
.auth_ref
556 token
= auth_ref
['auth_token']
558 # Verify if the newly acquired token works.
559 nova
= NovaDriver(drv
)
560 flavors
= nova
.flavor_list()
561 self
.assertTrue(len(flavors
) > 1)
563 # Invalidate the token
564 token_manger
= ksclient
.tokens
.TokenManager(client
)
565 token_manger
.revoke_token(token
)
571 flavors
= nova
.flavor_list()
573 except nova_exception
.AuthorizationFailure
:
576 self
.assertTrue(unauth_exp
)
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
583 flavors
= nova
.flavor_list()
584 self
.assertTrue(len(flavors
) > 1)
586 def test_v3_Keystone(self
):
587 # Keystone v3 authentication
590 drv
= KeystoneDriverV3(openstack_V3_info
['username'],
591 openstack_V3_info
['password'],
592 openstack_V3_info
['auth_url'],
593 openstack_V3_info
['project_name'],
595 openstack_V3_info
['user_domain_name'],
596 openstack_V3_info
['project_domain_name'])
597 client
= drv
._get
_keystone
_connection
()
600 self
.assertFalse(auth_exp
)
602 # Incorrect domain being to passed to v3 Keystone API
605 drv
= KeystoneDriverV3(openstack_V3_info
['username'],
606 openstack_V3_info
['password'],
607 openstack_V3_info
['auth_url'],
608 openstack_V3_info
['project_name'],
611 openstack_V3_info
['project_domain_name'])
612 client
= drv
._get
_keystone
_connection
()
615 self
.assertTrue(auth_exp
)
617 # Keystone v3 authentication-Backward compatabilty test
620 drv
= KeystoneDriverV3(openstack_info
['username'],
621 openstack_info
['password'],
622 openstack_info
['auth_url'],
623 openstack_info
['project_name'],
625 openstack_info
['user_domain_name'],
626 openstack_info
['project_domain_name'])
627 client
= drv
._get
_keystone
_connection
()
630 self
.assertFalse(auth_exp
)
632 # Keystone v3 authentication-Backward compatabilty
635 drv
= KeystoneDriverV3(openstack_info
['username'],
636 openstack_info
['password'],
637 openstack_info
['auth_url'],
638 openstack_info
['project_name'],
642 client
= drv
._get
_keystone
_connection
()
645 self
.assertFalse(auth_exp
)
647 # Keystone v2 authentication
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'],
656 client
= drv2
._get_keystone_connection()
659 self
.assertFalse(auth_exp
)
661 @unittest.skip("Skipping test_vm_operations")
662 def test_vm_operations(self
):
664 Primary goal: Create/Query/Delete VM in openstack installation.
665 Secondary goal: VM pause/resume operations on VM.
668 logger
.info("Openstack-CAL-Test: Starting VM Operations test")
671 data
, vm_id
= self
._create
_vm
(self
._flavor
, self
._image
)
676 self
._start
_vm
(vm_id
)
678 vm_data
= VmData(data
.host_name
, data
.management_ip
)
679 self
.assert_vm(vm_data
, self
._flavor
)
682 self
._reboot
_vm
(vm_id
)
684 self
._delete
_vm
(vm_id
)
687 def _get_network_info_request(self
):
689 Returns request object of type RwcalYang.NetworkInfoItem
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
704 def _create_network(self
):
706 Create a network and verify that network creation is successful
708 network
= self
._get
_network
_info
_request
()
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
)
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
))
722 def _delete_network(self
, net_id
):
724 Delete network and verify that delete operation is successful
726 rc
, rs
= self
.cal
.get_network(self
._acct
, net_id
)
727 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
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
)
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))
741 @unittest.skip("Skipping test_network_operations")
742 def test_network_operations(self
):
744 Create/Delete Networks
746 logger
.info("Openstack-CAL-Test: Starting Network Operation test")
749 net_id
= self
._create
_network
()
752 self
._delete
_network
(net_id
)
754 def _get_port_info_request(self
, network_id
, vm_id
):
756 Returns an object of type RwcalYang.PortInfoItem
758 port
= RwcalYang
.PortInfoItem()
759 port
.port_name
= 'rift.cal.unittest.port'
760 port
.network_id
= network_id
765 def _create_port(self
, net_id
, vm_id
= None):
767 Create a port in network with network_id: net_id and verifies that operation is successful
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
))
772 logger
.info("Openstack-CAL-Test: Creating a port in network with network_id: %s" %(net_id))
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
)
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
))
786 def _delete_port(self
, port_id
):
788 Deletes a port and verifies that operation is successful
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
))
795 self
.cal
.delete_port(self
._acct
, port_id
)
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))
803 def _monitor_port(self
, port_id
, expected_state
):
805 Monitor the port state until it reaches expected_state
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
:
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
))
818 @unittest.skip("Skipping test_port_operations_with_vm")
819 def test_port_operations_with_vm(self
):
821 Create/Delete Ports in a network and associate it with a VM
823 logger
.info("Openstack-CAL-Test: Starting Port Operation test with VM")
825 ### First create a network
826 net_id
= self
._create
_network
()
829 data
, vm_id
= self
._create
_vm
(self
._flavor
, self
._image
)
831 ### Now create Port which connects VM to Network
832 port_id
= self
._create
_port
(net_id
, vm_id
)
834 ### Verify that port goes to active state
835 self
._monitor
_port
(port_id
, 'ACTIVE')
838 self
._delete
_vm
(vm_id
)
841 self
._delete
_port
(port_id
)
843 ### Delete the network
844 self
._delete
_network
(net_id
)
846 @unittest.skip("Skipping test_create_vm_with_port")
847 def test_create_vm_with_port(self
):
849 Create VM and add ports to it during boot time.
851 logger
.info("Openstack-CAL-Test: Starting Create VM with port test")
853 ### First create a network
854 net_id
= self
._create
_network
()
856 ### Now create Port which connects VM to Network
857 port_id
= self
._create
_port
(net_id
)
860 data
, vm_id
= self
._create
_vm
(self
._flavor
, self
._image
, [port_id
])
862 ### Verify that port goes to active state
863 self
._monitor
_port
(port_id
, 'ACTIVE')
866 self
._delete
_vm
(vm_id
)
869 self
._delete
_port
(port_id
)
871 ### Delete the network
872 self
._delete
_network
(net_id
)
874 @unittest.skip("Skipping test_get_vdu_list")
875 def test_get_vdu_list(self
):
877 Test the get_vdu_list API
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
)
888 @unittest.skip("Skipping test_get_virtual_link_list")
889 def test_get_virtual_link_list(self
):
891 Test the get_virtual_link_list API
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
)
901 def _get_virtual_link_request_info(self
):
903 Returns object of type RwcalYang.VirtualLinkReqParams
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
917 def _get_vdu_request_info(self
, virtual_link_id
):
919 Returns object of type RwcalYang.VDUInitParams
921 vdu
= RwcalYang
.VDUInitParams()
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()
930 c1
.virtual_link_id
= virtual_link_id
931 c1
.type_yang
= 'VIRTIO'
934 def _get_vdu_modify_request_info(self
, vdu_id
, virtual_link_id
):
936 Returns object of type RwcalYang.VDUModifyParams
938 vdu
= RwcalYang
.VDUModifyParams()
940 c1
= vdu
.connection_points_add
.add()
941 c1
.name
= "c_modify1"
942 c1
.virtual_link_id
= virtual_link_id
946 #@unittest.skip("Skipping test_create_delete_virtual_link_and_vdu")
947 def test_create_delete_virtual_link_and_vdu(self
):
951 logger
.info("Openstack-CAL-Test: Test Create Virtual Link API")
952 vlink_req
= self
._get
_virtual
_link
_request
_info
()
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
)
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
)
965 vdu_req
= self
._get
_vdu
_request
_info
(vlink_id
)
966 logger
.info("Openstack-CAL-Test: Test Create VDU API")
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
)
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
)
978 ### Wait until vdu_state is active
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':
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))
991 vlink_req
= self
._get
_virtual
_link
_request
_info
()
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
)
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
)
1005 ### Lets delete the VDU
1006 self
.cal
.delete_vdu(self
._acct
, vdu_id
)
1008 ### Lets delete the Virtual Link
1009 self
.cal
.delete_virtual_link(self
._acct
, vlink_id
)
1011 ### Lets delete the Virtual Link-2
1012 self
.cal
.delete_virtual_link(self
._acct
, vlink_id2
)
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
)
1021 rc
, rsp
= self
.cal
.get_virtual_link_list(self
._acct
)
1022 self
.assertEqual(rc
, RwStatus
.SUCCESS
)
1024 for virtual_link
in rsp
.virtual_link_info_list
:
1025 self
.assertNotEqual(virtual_link
.virtual_link_id
, vlink_id
)
1027 logger
.info("Openstack-CAL-Test: VDU/Virtual Link create-delete test successfully completed")
1029 class VmData(object):
1030 """A convenience class that provides all the stats and EPA Attributes
1031 from the VM provided
1033 def __init__(self
, host
, mgmt_ip
):
1036 host (str): host name.
1037 mgmt_ip (str): The IP of the newly created VM.
1039 # Sleep for 20s to ensure the VM is UP and ready to run commands
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
)
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 /",
1053 self
._pci
_data
= self
._exec
('lspci -m | grep "10-Gigabit"')
1055 def _get_data(self
,):
1056 """Runs the command and store the output in a python dict.
1059 dict: Containing all key => value pairs.
1062 cmds
= ["lscpu", 'less /proc/meminfo']
1064 ssh_out
= self
._exec
(cmd
)
1065 content
.update(self
._convert
_to
_dict
(ssh_out
))
1068 def _exec_and_clean(self
, cmd
, line_no
=0):
1069 """A convenience method to run a command and extract the specified line
1073 cmd (str): Command to execute
1074 line_no (int, optional): Default to 0, extracts the first line.
1077 str: line_no of the output of the command.
1079 output
= self
._exec
(cmd
)[line_no
]
1080 output
= ' '.join(output
.split())
1081 return output
.strip()
1083 def _exec(self
, cmd
):
1084 """Thin wrapper that runs the command and returns the stdout data
1087 cmd (str): Command to execute.
1090 list: Contains the command output.
1092 _
, ssh_out
, _
= self
.client
.exec_command(
1093 "/usr/rift/bin/ssh_root {} {}".format(self
.ip
,
1095 return ssh_out
.readlines()
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 " ".
1102 content (list): A list containing the stdout.
1105 dict: containing stat attribute => value.
1108 for line
in content
:
1109 line
= ' '.join(line
.split())
1111 key
, value
= line
.split(":")
1113 key
, value
= line
.split(" ")
1114 key
, value
= key
.strip(), value
.strip()
1115 flattened
[key
] = value
1120 disk
= self
._disk
_space
.replace("G", "")
1124 def numa_node_count(self
):
1125 numa_cores
= self
._data
['NUMA node(s)']
1126 numa_cores
= int(numa_cores
)
1131 cores
= int(self
._data
['CPU(s)'])
1135 def cpu_threads(self
):
1136 threads
= int(self
._data
['Thread(s) per core'])
1141 memory
= self
._data
['MemTotal']
1142 memory
= int(memory
.replace("kB", ""))/1000/1000
1146 def memory_page_size(self
):
1147 return self
._page
_size
1150 def pci_passthrough_device_list(self
):
1151 return self
._pci
_data
1154 if __name__
== "__main__":
1155 logging
.basicConfig(level
=logging
.DEBUG
)