RIFT OSM R1 Initial Submission
[osm/SO.git] / rwcal / test / test_rwcal_openstack.py
diff --git a/rwcal/test/test_rwcal_openstack.py b/rwcal/test/test_rwcal_openstack.py
new file mode 100644 (file)
index 0000000..4ce494b
--- /dev/null
@@ -0,0 +1,1057 @@
+
+# 
+#   Copyright 2016 RIFT.IO Inc
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+
+import datetime
+import logging
+import time
+import unittest
+import hashlib
+
+import novaclient.exceptions as nova_exception
+import paramiko
+import rw_peas
+import rwlogger
+from keystoneclient import v3 as ksclient
+
+from gi.repository import RwcalYang
+from gi.repository.RwTypes import RwStatus
+from rift.rwcal.openstack.openstack_drv import KeystoneDriver, NovaDriver
+
+logger = logging.getLogger('rwcal-openstack')
+
+#
+# Important information about openstack installation. This needs to be manually verified 
+#
+openstack_info = {
+    'username'           : 'pluto',
+    'password'           : 'mypasswd',
+    'auth_url'           : 'http://10.66.4.14:5000/v3/',
+    'project_name'       : 'demo',
+    'mgmt_network'       : 'private',
+    'reserved_flavor'    : 'm1.medium',
+    'reserved_image'     : 'rift-root-latest.qcow2',
+    'physical_network'   : None,
+    'network_type'       : None,
+    'segmentation_id'    : None
+    }
+
+
+def get_cal_account():
+    """
+    Creates an object for class RwcalYang.CloudAccount()
+    """
+    account                        = RwcalYang.CloudAccount()
+    account.account_type           = "openstack"
+    account.openstack.key          = openstack_info['username']
+    account.openstack.secret       = openstack_info['password']
+    account.openstack.auth_url     = openstack_info['auth_url']
+    account.openstack.tenant       = openstack_info['project_name']
+    account.openstack.mgmt_network = openstack_info['mgmt_network']
+    return account
+
+def get_cal_plugin():
+    """
+    Loads rw.cal plugin via libpeas
+    """
+    plugin = rw_peas.PeasPlugin('rwcal_openstack', 'RwCal-1.0')
+    engine, info, extension = plugin()
+
+    # Get the RwLogger context
+    rwloggerctx = rwlogger.RwLog.Ctx.new("Cal-Log")
+
+    cal = plugin.get_interface("Cloud")
+    try:
+        rc = cal.init(rwloggerctx)
+        assert rc == RwStatus.SUCCESS
+    except:
+        logger.error("ERROR:Cal plugin instantiation failed. Aborting tests")
+    else:
+        logger.info("Openstack Cal plugin successfully instantiated")
+    return cal 
+
+
+class OpenStackTest(unittest.TestCase):
+    NodeID = "123456789012345" # Some random number to test VM tagging
+    MemoryPageSize = "LARGE"
+    CpuPolicy = "DEDICATED"
+    CpuThreadPolicy = "SEPARATE"
+    CpuThreads = 1
+    NumaNodeCount = 2
+    HostTrust = "trusted"
+    PCIPassThroughAlias = "PCI_10G_ALIAS"
+    SEG_ID = openstack_info['segmentation_id']
+    
+    def setUp(self):
+        """
+        Assumption:
+         - It is assumed that openstack install has a flavor and image precreated.
+         - Flavor_name: x1.xlarge
+         - Image_name : rwimage
+
+        If these resources are not then this test will fail.
+        """
+        self._acct = get_cal_account()
+        logger.info("Openstack-CAL-Test: setUp")
+        self.cal   = get_cal_plugin()
+        logger.info("Openstack-CAL-Test: setUpEND")
+        
+        # First check for VM Flavor and Image and get the corresponding IDs
+        rc, rs = self.cal.get_flavor_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        flavor_list = [ flavor for flavor in rs.flavorinfo_list if flavor.name == openstack_info['reserved_flavor'] ]
+        self.assertNotEqual(len(flavor_list), 0)
+        self._flavor = flavor_list[0]
+
+        rc, rs = self.cal.get_image_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        image_list = [ image for image in rs.imageinfo_list if image.name == openstack_info['reserved_image'] ]
+        self.assertNotEqual(len(image_list), 0)
+        self._image = image_list[0]
+
+        rc, rs = self.cal.get_network_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        networks = [ network for network in rs.networkinfo_list if (network.network_name == 'rift.cal.unittest.network' or network.network_name == 'rift.cal.virtual_link') ]
+        for network in networks:
+            self.cal.delete_virtual_link(self._acct, network.network_id)
+            
+    def tearDown(self):
+        logger.info("Openstack-CAL-Test: tearDown")
+        
+
+    def _md5(fname, blksize=1048576):
+        hash_md5 = hashlib.md5()
+        with open(fname, "rb") as f:
+            for chunk in iter(lambda: f.read(blksize), b""):
+                hash_md5.update(chunk)
+        return hash_md5.hexdigest()
+
+    @unittest.skip("Skipping test_list_flavors")        
+    def test_list_flavor(self):
+        """
+        List existing flavors from openstack installation
+        """
+        logger.info("Openstack-CAL-Test: Starting List Flavors Test")
+        rc, rsp = self.cal.get_flavor_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Received %d flavors" %(len(rsp.flavorinfo_list)))
+        for flavor in rsp.flavorinfo_list:
+            rc, flv = self.cal.get_flavor(self._acct, flavor.id)
+            self.assertEqual(rc, RwStatus.SUCCESS)
+            self.assertEqual(flavor.id, flv.id)
+        
+    @unittest.skip("Skipping test_list_images")                    
+    def test_list_images(self):
+        """
+        List existing images from openstack installation
+        """
+        logger.info("Openstack-CAL-Test: Starting List Images Test")
+        rc, rsp = self.cal.get_image_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Received %d images" %(len(rsp.imageinfo_list)))
+        #for image in rsp.imageinfo_list:
+        #    rc, img = self.cal.get_image(self._acct, image.id)
+        #    self.assertEqual(rc, RwStatus.SUCCESS)
+        #    self.assertEqual(image.id, img.id)
+        
+    @unittest.skip("Skipping test_list_vms")                
+    def test_list_vms(self):
+        """
+        List existing VMs from openstack installation
+        """
+        logger.info("Openstack-CAL-Test: Starting List VMs Test")
+        rc, rsp = self.cal.get_vm_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Received %d VMs" %(len(rsp.vminfo_list)))
+        for vm in rsp.vminfo_list:
+            rc, server = self.cal.get_vm(self._acct, vm.vm_id)
+            self.assertEqual(vm.vm_id, server.vm_id)
+            
+    @unittest.skip("Skipping test_list_networks")                            
+    def test_list_networks(self):
+        """
+        List existing Network from openstack installation
+        """
+        logger.info("Openstack-CAL-Test: Starting List Networks Test")
+        rc, rsp = self.cal.get_network_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Received %d Networks" %(len(rsp.networkinfo_list)))
+        for network in rsp.networkinfo_list:
+            rc, net = self.cal.get_network(self._acct, network.network_id)
+            self.assertEqual(network.network_id, net.network_id)
+        
+    @unittest.skip("Skipping test_list_ports")                                    
+    def test_list_ports(self):
+        """
+        List existing Ports from openstack installation
+        """
+        logger.info("Openstack-CAL-Test: Starting List Ports Test")
+        rc, rsp = self.cal.get_port_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        assert(rc == RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Received %d Ports" %(len(rsp.portinfo_list)))
+        for port in rsp.portinfo_list:
+            rc, p = self.cal.get_port(self._acct, port.port_id)
+            self.assertEqual(port.port_id, p.port_id)
+
+    def _get_image_info_request(self):
+        """
+        Returns request object of type RwcalYang.ImageInfoItem()
+        """
+        img = RwcalYang.ImageInfoItem()
+        img.name = "rift.cal.unittest.image"
+        img.location = '/net/sharedfiles/home1/common/vm/rift-root-latest.qcow2'
+        img.disk_format = "qcow2"
+        img.container_format = "bare"
+        img.checksum = self._md5(img.location)
+        return img
+
+    def _get_image_info(self, img_id):
+        """
+        Checks the image status until it becomes active or timeout occurs (100sec)
+        Returns the image_info dictionary
+        """
+        rs = None
+        rc = None
+        for i in range(100):
+            rc, rs = self.cal.get_image(self._acct, img_id)
+            self.assertEqual(rc, RwStatus.SUCCESS)
+            logger.info("Openstack-CAL-Test: Image (image_id: %s) reached state : %s" %(img_id, rs.state))
+            if rs.state == 'active':
+                break
+            else:
+                time.sleep(2) # Sleep for a second
+        return rs
+    
+    @unittest.skip("Skipping test_create_delete_image")                            
+    def test_create_delete_image(self):
+        """
+        Create/Query/Delete a new image in openstack installation
+        """
+        logger.info("Openstack-CAL-Test: Starting Image create test")
+        img = self._get_image_info_request()
+        rc, img_id = self.cal.create_image(self._acct, img)
+        logger.info("Openstack-CAL-Test: Created Image with image_id: %s" %(img_id))
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        img_info = self._get_image_info(img_id)
+        self.assertNotEqual(img_info, None)
+        self.assertEqual(img_id, img_info.id)
+        logger.info("Openstack-CAL-Test: Image (image_id: %s) reached state : %s" %(img_id, img_info.state))
+        self.assertEqual(img_info.has_field('checksum'), True)
+        #self.assertEqual(img_info.checksum, OpenStackTest.IMG_Checksum)
+        logger.info("Openstack-CAL-Test: Initiating Delete Image operation for image_id: %s" %(img_id))
+        rc = self.cal.delete_image(self._acct, img_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Image (image_id: %s) successfully deleted" %(img_id))
+
+    def _get_flavor_info_request(self):
+        """
+        Returns request object of type RwcalYang.FlavorInfoItem()
+        """
+        flavor                                     = RwcalYang.FlavorInfoItem()
+        flavor.name                                = 'rift.cal.unittest.flavor'
+        flavor.vm_flavor.memory_mb                 = 16384 # 16GB
+        flavor.vm_flavor.vcpu_count                = 4 
+        flavor.vm_flavor.storage_gb                = 40 # 40GB
+        flavor.guest_epa.mempage_size              = OpenStackTest.MemoryPageSize
+        flavor.guest_epa.cpu_pinning_policy        = OpenStackTest.CpuPolicy
+        flavor.guest_epa.cpu_thread_pinning_policy = OpenStackTest.CpuThreadPolicy
+        flavor.guest_epa.numa_node_policy.node_cnt = OpenStackTest.NumaNodeCount
+        for i in range(OpenStackTest.NumaNodeCount):
+            node = flavor.guest_epa.numa_node_policy.node.add()
+            node.id = i
+            if i == 0:
+                node.vcpu = [0,1]
+            elif i == 1:
+                node.vcpu = [2,3]
+            node.memory_mb = 8196
+        dev = flavor.guest_epa.pcie_device.add()
+        dev.device_id = OpenStackTest.PCIPassThroughAlias
+        dev.count = 1
+        return flavor
+        
+    @unittest.skip("Skipping test_create_delete_flavor")                            
+    def test_create_delete_flavor(self):
+        """
+        Create/Query/Delete a new flavor in openstack installation
+        """
+        logger.info("Openstack-CAL-Test: Starting Image create/delete test")
+
+        ### Delete any previously created flavor with name rift.cal.unittest.flavor
+        rc, rs = self.cal.get_flavor_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        flavor_list = [ flavor for flavor in rs.flavorinfo_list if flavor.name == 'rift.cal.unittest.flavor' ]
+        if flavor_list:
+            rc = self.cal.delete_flavor(self._acct, flavor_list[0].id)
+            self.assertEqual(rc, RwStatus.SUCCESS)
+        
+        flavor = self._get_flavor_info_request()
+        rc, flavor_id = self.cal.create_flavor(self._acct, flavor)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        
+        logger.info("Openstack-CAL-Test: Created new flavor with flavor_id : %s" %(flavor_id))
+        rc, rs = self.cal.get_flavor(self._acct, flavor_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        self.assertEqual(rs.id, flavor_id)
+
+        # Verify EPA Attributes
+        self.assertEqual(rs.guest_epa.mempage_size, OpenStackTest.MemoryPageSize)
+        self.assertEqual(rs.guest_epa.cpu_pinning_policy, OpenStackTest.CpuPolicy)
+        self.assertEqual(rs.guest_epa.cpu_thread_pinning_policy, OpenStackTest.CpuThreadPolicy)
+        self.assertEqual(rs.guest_epa.numa_node_policy.node_cnt, OpenStackTest.NumaNodeCount)
+        self.assertEqual(len(rs.guest_epa.pcie_device), 1)
+        self.assertEqual(rs.guest_epa.pcie_device[0].device_id, OpenStackTest.PCIPassThroughAlias)
+        self.assertEqual(rs.guest_epa.pcie_device[0].count, 1)
+        logger.info("Openstack-CAL-Test: Initiating delete for flavor_id : %s" %(flavor_id))
+        rc = self.cal.delete_flavor(self._acct, flavor_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        # Check that flavor does not exist anymore in list_flavor
+        rc, rs = self.cal.get_flavor_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        flavor_list = [ flavor for flavor in rs.flavorinfo_list if flavor.id == flavor_id ]
+        # Flavor List should be empty
+        self.assertEqual(len(flavor_list), 0)
+        logger.info("Openstack-CAL-Test: Flavor (flavor_id: %s) successfully deleted" %(flavor_id))
+
+    def _get_vm_info_request(self, flavor_id, image_id):
+        """
+        Returns request object of type RwcalYang.VMInfoItem
+        """
+        vm = RwcalYang.VMInfoItem()
+        vm.vm_name = 'rift.cal.unittest.vm'
+        vm.flavor_id = flavor_id
+        vm.image_id  = image_id
+        vm.cloud_init.userdata = ''
+        vm.user_tags.node_id  = OpenStackTest.NodeID
+        return vm
+
+    def _check_vm_state(self, vm_id, expected_state):
+        """
+        Wait until VM reaches particular state (expected_state). 
+        """
+        # Wait while VM goes to required state
+
+        for i in range(50): # 50 poll iterations...
+            rc, rs = self.cal.get_vm(self._acct, vm_id)
+            self.assertEqual(rc, RwStatus.SUCCESS)
+            logger.info("Openstack-CAL-Test: VM vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
+            if rs.state == expected_state:
+                break
+            else:
+                time.sleep(1)
+
+        rc, rs = self.cal.get_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        self.assertEqual(rs.state, expected_state)
+
+    def _create_vm(self, flavor, image, port_list = None):
+        """
+        Create VM and perform validity checks
+        """
+        logger.info("Openstack-CAL-Test: Using image : %s and flavor : %s " %(image.name, flavor.name))
+        vm = self._get_vm_info_request(flavor.id, image.id)
+
+        if port_list:
+            for port_id in port_list:
+                port = vm.port_list.add()
+                port.port_id = port_id 
+
+        rc, vm_id = self.cal.create_vm(self._acct, vm)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        ### Check if VM creation is successful
+        rc, rs = self.cal.get_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Successfully created VM with vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
+
+        ### Ensure the VM state is active
+        self._check_vm_state(vm_id, 'ACTIVE')
+
+        ### Ensure that userdata tags are set as expected
+        rc, rs = self.cal.get_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        self.assertEqual(rs.user_tags.has_field('node_id'), True)
+        self.assertEqual(getattr(rs.user_tags, 'node_id'), OpenStackTest.NodeID)
+        logger.info("Openstack-CAL-Test: Successfully verified the user tags for VM-ID: %s" %(vm_id))
+        return rs, vm_id
+
+    def _delete_vm(self, vm_id):
+        """
+        Delete VM and perform validity checks
+        """
+        rc, rs = self.cal.get_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        logger.info("Openstack-CAL-Test: Initiating VM Delete operation on VM vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
+
+        rc = self.cal.delete_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        for i in range(50):
+            # Check if VM still exists
+            rc, rs = self.cal.get_vm_list(self._acct)
+            self.assertEqual(rc, RwStatus.SUCCESS)
+            vm_list = [vm for vm in rs.vminfo_list if vm.vm_id == vm_id]
+            if not len(vm_list):
+                break
+        
+        rc, rs = self.cal.get_vm_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        vm_list = [vm for vm in rs.vminfo_list if vm.vm_id == vm_id]
+        self.assertEqual(len(vm_list), 0)
+        logger.info("Openstack-CAL-Test: VM with vm_id : %s successfully deleted" %(vm_id))
+
+    def _stop_vm(self, vm_id):
+        """
+        Stop VM and perform validity checks
+        """
+        rc, rs = self.cal.get_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Initiating Stop VM operation on VM vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
+        rc = self.cal.stop_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        ### Ensure that VM state is SHUTOFF
+        self._check_vm_state(vm_id, 'SHUTOFF')
+        
+        
+    def _start_vm(self, vm_id):
+        """
+        Starts VM and performs validity checks
+        """
+        rc, rs = self.cal.get_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Initiating Start VM operation on VM vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
+        rc = self.cal.start_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        ### Ensure that VM state is ACTIVE
+        self._check_vm_state(vm_id, 'ACTIVE')
+
+        
+    def _reboot_vm(self, vm_id):
+        """
+        Reboot VM and perform validity checks
+        """
+        rc, rs = self.cal.get_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Initiating Reboot VM operation on VM vm_id : %s. Current VM state : %s " %(vm_id, rs.state))
+        rc = self.cal.reboot_vm(self._acct, vm_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        ### Ensure that VM state is ACTIVE
+        self._check_vm_state(vm_id, 'ACTIVE')
+
+    def assert_vm(self, vm_data, flavor):
+        """Verify the newly created VM for attributes specified in the flavor.
+
+        Args:
+            vm_data (VmData): Instance of the newly created VM
+            flavor (FlavorInfoItem): Config flavor.
+        """
+        vm_config = flavor
+
+        # Page size seems to be 4096, regardless of the page size name.
+        page_lookup = {"large": '4096', "small": '4096'}
+        FIELDS = ["vcpus", "cpu_threads", "memory_page_size", "disk",
+                  "numa_node_count", "memory", "pci_passthrough_device_list"]
+
+        for field in FIELDS:
+            if field not in vm_config:
+                continue
+
+            vm_value = getattr(vm_data, field)
+            config_value = getattr(vm_config, field)
+
+            if field == "memory_page_size":
+                config_value = page_lookup[config_value]
+
+            if field == "memory":
+                config_value = int(config_value/1000)
+
+            if field == "pci_passthrough_device_list":
+                config_value = len(config_value)
+                vm_value = len(vm_value)
+
+            self.assertEqual(vm_value, config_value)
+
+    @unittest.skip("Skipping test_vm_epa_attributes")
+    def test_vm_epa_attributes(self):
+        """
+        Primary goal: To create a VM with the specified EPA Attributes
+        Secondary goal: To verify flavor creation/delete
+        """
+
+        logger.info("Openstack-CAL-Test: Starting VM(EPA) create/delete test")
+        flavor = self._get_flavor_info_request()
+   
+        rc, flavor_id = self.cal.do_create_flavor(self._acct, flavor)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        flavor.id = flavor_id
+
+        data, vm_id = self._create_vm(flavor, self._image)
+
+        vm_data = VmData(data.host_name, data.management_ip)
+        self.assert_vm(vm_data, flavor)
+
+        self._delete_vm(vm_id)
+
+        rc = self.cal.do_delete_flavor(self._acct, flavor_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+    @unittest.skip("Skipping test_expiry_token")
+    def test_expiry_token(self):
+        """
+        Primary goal: To verify if we are refreshing the expired tokens.
+        """
+        logger.info("Openstack-CAL-Test: Starting token refresh test")
+        drv = KeystoneDriver(
+                openstack_info['username'],
+                openstack_info['password'],
+                openstack_info['auth_url'],
+                openstack_info['project_name'])
+        # Get hold of the client instance need for Token Manager
+        client = drv._get_keystone_connection()
+
+        auth_ref = client.auth_ref
+        token = auth_ref['auth_token']
+
+        # Verify if the newly acquired token works.
+        nova = NovaDriver(drv)
+        flavors = nova.flavor_list()
+        self.assertTrue(len(flavors) > 1)
+
+        # Invalidate the token
+        token_manger = ksclient.tokens.TokenManager(client)
+        token_manger.revoke_token(token)
+
+        time.sleep(10)
+
+        unauth_exp = False
+        try:
+            flavors = nova.flavor_list()
+            print (flavors)
+        except nova_exception.AuthorizationFailure:
+            unauth_exp = True
+
+        self.assertTrue(unauth_exp)
+
+        # Explicitly reset the expire time, to test if we acquire a new token
+        now = datetime.datetime.utcnow()
+        time_str = format(now, "%Y-%m-%dT%H:%M:%S.%fZ")
+        drv._get_keystone_connection().auth_ref['expires_at'] = time_str
+
+        flavors = nova.flavor_list()
+        self.assertTrue(len(flavors) > 1)
+
+    @unittest.skip("Skipping test_vm_operations")                            
+    def test_vm_operations(self):
+        """
+        Primary goal: Create/Query/Delete VM in openstack installation.
+        Secondary goal: VM pause/resume operations on VM.
+
+        """
+        logger.info("Openstack-CAL-Test: Starting VM Operations test")
+
+        # Create VM
+        data, vm_id = self._create_vm(self._flavor, self._image)
+
+        # Stop VM
+        self._stop_vm(vm_id)
+        # Start VM
+        self._start_vm(vm_id)
+
+        vm_data = VmData(data.host_name, data.management_ip)
+        self.assert_vm(vm_data, self._flavor)
+
+        # Reboot VM
+        self._reboot_vm(vm_id)
+        ### Delete the VM
+        self._delete_vm(vm_id)
+
+        
+    def _get_network_info_request(self):
+        """
+        Returns request object of type RwcalYang.NetworkInfoItem
+        """
+        network                            = RwcalYang.NetworkInfoItem()
+        network.network_name               = 'rift.cal.unittest.network'
+        network.subnet                     = '192.168.16.0/24'
+        if openstack_info['physical_network']:
+            network.provider_network.physical_network = openstack_info['physical_network']
+        if openstack_info['network_type']:
+            network.provider_network.overlay_type     = openstack_info['network_type']
+        if OpenStackTest.SEG_ID:
+            network.provider_network.segmentation_id  = OpenStackTest.SEG_ID
+            OpenStackTest.SEG_ID += 1
+        return network
+
+
+    def _create_network(self):
+        """
+        Create a network and verify that network creation is successful
+        """
+        network = self._get_network_info_request()
+
+        ### Create network
+        logger.info("Openstack-CAL-Test: Creating a network with name : %s" %(network.network_name))
+        rc, net_id = self.cal.create_network(self._acct, network)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        ### Verify network is created successfully
+        rc, rs = self.cal.get_network(self._acct, net_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Successfully create Network : %s  with id : %s." %(network.network_name, net_id ))
+
+        return net_id
+
+    def _delete_network(self, net_id):
+        """
+        Delete network and verify that delete operation is successful
+        """
+        rc, rs = self.cal.get_network(self._acct, net_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        logger.info("Openstack-CAL-Test: Deleting a network with id : %s. " %(net_id))
+        rc = self.cal.delete_network(self._acct, net_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        
+        # Verify that network is no longer available via get_network_list API
+        rc, rs = self.cal.get_network_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        network_info = [ network for network in rs.networkinfo_list if network.network_id == net_id ]
+        self.assertEqual(len(network_info), 0)
+        logger.info("Openstack-CAL-Test: Successfully deleted Network with id : %s" %(net_id))
+        
+        
+    @unittest.skip("Skipping test_network_operations")                            
+    def test_network_operations(self):
+        """
+        Create/Delete Networks
+        """
+        logger.info("Openstack-CAL-Test: Starting Network Operation test")
+
+        ### Create Network
+        net_id = self._create_network()
+
+        ### Delete Network
+        self._delete_network(net_id)
+
+    def _get_port_info_request(self, network_id, vm_id):
+        """
+        Returns an object of type RwcalYang.PortInfoItem
+        """
+        port = RwcalYang.PortInfoItem()
+        port.port_name = 'rift.cal.unittest.port'
+        port.network_id = network_id
+        if vm_id != None:
+            port.vm_id = vm_id
+        return port
+
+    def _create_port(self, net_id, vm_id = None):
+        """
+        Create a port in network with network_id: net_id and verifies that operation is successful
+        """
+        if vm_id != None:
+            logger.info("Openstack-CAL-Test: Creating a port in network with network_id: %s and VM with vm_id: %s" %(net_id, vm_id))
+        else:
+            logger.info("Openstack-CAL-Test: Creating a port in network with network_id: %s" %(net_id))
+
+        ### Create Port
+        port = self._get_port_info_request(net_id, vm_id)
+        rc, port_id = self.cal.create_port(self._acct, port)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        ### Get Port
+        rc, rs = self.cal.get_port(self._acct, port_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Successfully create Port with id : %s. Port State :  %s" %(port_id, rs.port_state))
+
+        return port_id
+
+    def _delete_port(self, port_id):
+        """
+        Deletes a port and verifies that operation is successful
+        """
+        rc, rs = self.cal.get_port(self._acct, port_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Deleting Port with id : %s. Port State :  %s" %(port_id, rs.port_state))
+
+        ### Delete Port
+        self.cal.delete_port(self._acct, port_id)
+        
+        rc, rs = self.cal.get_port_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        port_list = [ port for port in rs.portinfo_list if port.port_id == port_id ]
+        self.assertEqual(len(port_list), 0)
+        logger.info("Openstack-CAL-Test: Successfully Deleted Port with id : %s" %(port_id))
+
+    def _monitor_port(self, port_id, expected_state):
+        """
+        Monitor the port state until it reaches expected_state
+        """
+        for i in range(50):
+            rc, rs = self.cal.get_port(self._acct, port_id)
+            self.assertEqual(rc, RwStatus.SUCCESS)
+            logger.info("Openstack-CAL-Test: Port with id : %s. Port State :  %s" %(port_id, rs.port_state))
+            if rs.port_state == expected_state:
+                break
+        rc, rs = self.cal.get_port(self._acct, port_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        self.assertEqual(rs.port_state, expected_state)
+        logger.info("Openstack-CAL-Test: Port with port_id : %s reached expected state  : %s" %(port_id, rs.port_state))
+            
+    @unittest.skip("Skipping test_port_operations_with_vm")
+    def test_port_operations_with_vm(self):
+        """
+        Create/Delete Ports in a network and associate it with a VM
+        """
+        logger.info("Openstack-CAL-Test: Starting Port Operation test with VM")
+
+        ### First create a network
+        net_id = self._create_network()
+
+        ### Create a VM
+        data, vm_id = self._create_vm(self._flavor, self._image)
+
+        ### Now create Port which connects VM to Network
+        port_id = self._create_port(net_id, vm_id)
+
+        ### Verify that port goes to active state
+        self._monitor_port(port_id, 'ACTIVE')
+
+        ### Delete VM
+        self._delete_vm(vm_id)
+        
+        ### Delete Port
+        self._delete_port(port_id)
+
+        ### Delete the network
+        self._delete_network(net_id)
+
+    @unittest.skip("Skipping test_create_vm_with_port")
+    def test_create_vm_with_port(self):
+        """
+        Create VM and add ports to it during boot time.
+        """
+        logger.info("Openstack-CAL-Test: Starting Create VM with port test")
+
+        ### First create a network
+        net_id = self._create_network()
+
+        ### Now create Port which connects VM to Network
+        port_id = self._create_port(net_id)
+
+        ### Create a VM
+        data, vm_id = self._create_vm(self._flavor, self._image, [port_id])
+
+        ### Verify that port goes to active state
+        self._monitor_port(port_id, 'ACTIVE')
+
+        ### Delete VM
+        self._delete_vm(vm_id)
+        
+        ### Delete Port
+        self._delete_port(port_id)
+
+        ### Delete the network
+        self._delete_network(net_id)
+
+    @unittest.skip("Skipping test_get_vdu_list")
+    def test_get_vdu_list(self):
+        """
+        Test the get_vdu_list API
+        """
+        logger.info("Openstack-CAL-Test: Test Get VDU List APIs")
+        rc, rsp = self.cal.get_vdu_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Received %d VDUs" %(len(rsp.vdu_info_list)))
+        for vdu in rsp.vdu_info_list:
+            rc, vdu2 = self.cal.get_vdu(self._acct, vdu.vdu_id)
+            self.assertEqual(vdu2.vdu_id, vdu.vdu_id)
+
+
+    @unittest.skip("Skipping test_get_virtual_link_list")
+    def test_get_virtual_link_list(self):
+        """
+        Test the get_virtual_link_list API
+        """
+        logger.info("Openstack-CAL-Test: Test Get virtual_link List APIs")
+        rc, rsp = self.cal.get_virtual_link_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Received %d virtual_links" %(len(rsp.virtual_link_info_list)))
+        for virtual_link in rsp.virtual_link_info_list:
+            rc, virtual_link2 = self.cal.get_virtual_link(self._acct, virtual_link.virtual_link_id)
+            self.assertEqual(virtual_link2.virtual_link_id, virtual_link.virtual_link_id)
+
+    def _get_virtual_link_request_info(self):
+        """
+        Returns object of type RwcalYang.VirtualLinkReqParams
+        """
+        vlink = RwcalYang.VirtualLinkReqParams()
+        vlink.name = 'rift.cal.virtual_link'
+        vlink.subnet = '192.168.1.0/24'
+        if openstack_info['physical_network']:
+            vlink.provider_network.physical_network = openstack_info['physical_network']
+        if openstack_info['network_type']:
+            vlink.provider_network.overlay_type     = openstack_info['network_type'].upper()
+        if OpenStackTest.SEG_ID:
+            vlink.provider_network.segmentation_id  = OpenStackTest.SEG_ID
+            OpenStackTest.SEG_ID += 1
+        return vlink
+        
+    def _get_vdu_request_info(self, virtual_link_id):
+        """
+        Returns object of type RwcalYang.VDUInitParams
+        """
+        vdu = RwcalYang.VDUInitParams()
+        vdu.name = "cal.vdu"
+        vdu.node_id = OpenStackTest.NodeID
+        vdu.image_id = self._image.id
+        vdu.flavor_id = self._flavor.id
+        vdu.vdu_init.userdata = ''
+        vdu.allocate_public_address = True
+        c1 = vdu.connection_points.add()
+        c1.name = "c_point1"
+        c1.virtual_link_id = virtual_link_id
+        c1.type_yang = 'VIRTIO'
+        return vdu
+
+    def _get_vdu_modify_request_info(self, vdu_id, virtual_link_id):
+        """
+        Returns object of type RwcalYang.VDUModifyParams
+        """
+        vdu = RwcalYang.VDUModifyParams()
+        vdu.vdu_id = vdu_id
+        c1 = vdu.connection_points_add.add()
+        c1.name = "c_modify1"
+        c1.virtual_link_id = virtual_link_id
+       
+        return vdu 
+        
+    #@unittest.skip("Skipping test_create_delete_virtual_link_and_vdu")
+    def test_create_delete_virtual_link_and_vdu(self):
+        """
+        Test to create VDU
+        """
+        logger.info("Openstack-CAL-Test: Test Create Virtual Link API")
+        vlink_req = self._get_virtual_link_request_info()
+
+        rc, rsp = self.cal.create_virtual_link(self._acct, vlink_req)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Created virtual_link with Id: %s" %rsp)
+        vlink_id = rsp
+        
+        #Check if virtual_link create is successful
+        rc, rsp = self.cal.get_virtual_link(self._acct, rsp)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        self.assertEqual(rsp.virtual_link_id, vlink_id)
+
+        # Now create VDU
+        vdu_req = self._get_vdu_request_info(vlink_id)
+        logger.info("Openstack-CAL-Test: Test Create VDU API")
+
+        rc, rsp = self.cal.create_vdu(self._acct, vdu_req)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Created vdu with Id: %s" %rsp)
+
+        vdu_id = rsp
+
+        ## Check if VDU create is successful
+        rc, rsp = self.cal.get_vdu(self._acct, rsp)
+        self.assertEqual(rsp.vdu_id, vdu_id)
+
+        ### Wait until vdu_state is active
+        for i in range(50):
+            rc, rs = self.cal.get_vdu(self._acct, vdu_id)
+            self.assertEqual(rc, RwStatus.SUCCESS)
+            logger.info("Openstack-CAL-Test: VDU with id : %s. Reached State :  %s" %(vdu_id, rs.state))
+            if rs.state == 'active':
+                break
+        rc, rs = self.cal.get_vdu(self._acct, vdu_id)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        self.assertEqual(rs.state, 'active')
+        logger.info("Openstack-CAL-Test: VDU with id : %s reached expected state  : %s" %(vdu_id, rs.state))
+        logger.info("Openstack-CAL-Test: VDUInfo: %s" %(rs))
+        
+        vlink_req = self._get_virtual_link_request_info()
+
+        ### Create another virtual_link
+        rc, rsp = self.cal.create_virtual_link(self._acct, vlink_req)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Created virtual_link with Id: %s" %rsp)
+        vlink_id2= rsp
+
+        ### Now exercise the modify_vdu_api
+        vdu_modify = self._get_vdu_modify_request_info(vdu_id, vlink_id2)
+        rc = self.cal.modify_vdu(self._acct, vdu_modify)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        logger.info("Openstack-CAL-Test: Modified vdu with Id: %s" %vdu_id)
+
+        ### Lets delete the VDU
+        self.cal.delete_vdu(self._acct, vdu_id)
+
+        ### Lets delete the Virtual Link
+        self.cal.delete_virtual_link(self._acct, vlink_id)
+
+        ### Lets delete the Virtual Link-2
+        self.cal.delete_virtual_link(self._acct, vlink_id2)
+
+        time.sleep(5)
+        ### Verify that VDU and virtual link are successfully deleted
+        rc, rsp = self.cal.get_vdu_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+        for vdu in rsp.vdu_info_list:
+            self.assertNotEqual(vdu.vdu_id, vdu_id)
+
+        rc, rsp = self.cal.get_virtual_link_list(self._acct)
+        self.assertEqual(rc, RwStatus.SUCCESS)
+
+        for virtual_link in rsp.virtual_link_info_list:
+            self.assertNotEqual(virtual_link.virtual_link_id, vlink_id)
+
+        logger.info("Openstack-CAL-Test: VDU/Virtual Link create-delete test successfully completed")
+
+
+class VmData(object):
+    """A convenience class that provides all the stats and EPA Attributes
+    from the VM provided
+    """
+    def __init__(self, host, mgmt_ip):
+        """
+        Args:
+            host (str): host name.
+            mgmt_ip (str): The IP of the newly created VM.
+        """
+        # Sleep for 20s to ensure the VM is UP and ready to run commands
+        time.sleep(20)
+        logger.info("Connecting to host: {} and IP: {}".format(host, mgmt_ip))
+        self.client = paramiko.SSHClient()
+        self.client.set_missing_host_key_policy(paramiko.WarningPolicy())
+        self.client.connect(host)
+        self.ip = mgmt_ip
+
+        # Get all data from the newly created VM.
+        self._data = self._get_data()
+        self._page_size = self._exec_and_clean("getconf PAGE_SIZE")
+        self._disk_space = self._exec_and_clean(
+                "df -kh --output=size /",
+                line_no=1)
+        self._pci_data = self._exec('lspci -m | grep "10-Gigabit"')
+
+    def _get_data(self,):
+        """Runs the command and store the output in a python dict.
+
+        Returns:
+            dict: Containing all key => value pairs.
+        """
+        content = {}
+        cmds = ["lscpu", 'less /proc/meminfo']
+        for cmd in cmds:
+            ssh_out = self._exec(cmd)
+            content.update(self._convert_to_dict(ssh_out))
+        return content
+
+    def _exec_and_clean(self, cmd, line_no=0):
+        """A convenience method to run a command and extract the specified line
+        number.
+
+        Args:
+            cmd (str): Command to execute
+            line_no (int, optional): Default to 0, extracts the first line.
+
+        Returns:
+            str: line_no of the output of the command.
+        """
+        output = self._exec(cmd)[line_no]
+        output = ' '.join(output.split())
+        return output.strip()
+
+    def _exec(self, cmd):
+        """Thin wrapper that runs the command and returns the stdout data
+
+        Args:
+            cmd (str): Command to execute.
+
+        Returns:
+            list: Contains the command output.
+        """
+        _, ssh_out, _ = self.client.exec_command(
+                "/usr/rift/bin/ssh_root {} {}".format(self.ip,
+                                                      cmd))
+        return ssh_out.readlines()
+
+    def _convert_to_dict(self, content):
+        """convenience method that cleans and stores the line into dict.
+        data is split based on ":" or " ".
+
+        Args:
+            content (list): A list containing the stdout.
+
+        Returns:
+            dict: containing stat attribute => value.
+        """
+        flattened = {}
+        for line in content:
+            line = ' '.join(line.split())
+            if ":" in line:
+                key, value = line.split(":")
+            else:
+                key, value = line.split(" ")
+            key, value = key.strip(), value.strip()
+            flattened[key] = value
+        return flattened
+
+    @property
+    def disk(self):
+        disk = self._disk_space.replace("G", "")
+        return int(disk)
+
+    @property
+    def numa_node_count(self):
+        numa_cores = self._data['NUMA node(s)']
+        numa_cores = int(numa_cores)
+        return numa_cores
+
+    @property
+    def vcpus(self):
+        cores = int(self._data['CPU(s)'])
+        return cores
+
+    @property
+    def cpu_threads(self):
+        threads = int(self._data['Thread(s) per core'])
+        return threads
+
+    @property
+    def memory(self):
+        memory = self._data['MemTotal']
+        memory = int(memory.replace("kB", ""))/1000/1000
+        return int(memory)
+
+    @property
+    def memory_page_size(self):
+        return self._page_size
+
+    @property
+    def pci_passthrough_device_list(self):
+        return self._pci_data
+
+
+if __name__ == "__main__":
+    logging.basicConfig(level=logging.INFO)
+    unittest.main()