CAL refactoring
[osm/SO.git] / rwcal / plugins / vala / rwcal_openstack / rwcal_openstack.py
index 2be896a..52bd574 100644 (file)
@@ -19,24 +19,29 @@ import contextlib
 import logging
 import os
 import subprocess
-import uuid
 import tempfile
 import yaml
 
+import gi
+gi.require_version('RwSdn', '1.0')
+gi.require_version('RwCal', '1.0')
+gi.require_version('RwcalYang', '1.0')
+
 import rift.rwcal.openstack as openstack_drv
+
+
 import rw_status
 import rift.cal.rwcal_status as rwcal_status
 import rwlogger
 import neutronclient.common.exceptions as NeutronException
 import keystoneclient.exceptions as KeystoneExceptions
-import tornado
-import gi
 
-gi.require_version('RwSdn', '1.0')
 
 from gi.repository import (
     GObject,
     RwCal,
+    RwSdn, # Vala package
+    RwsdnYang,
     RwTypes,
     RwcalYang)
 
@@ -50,8 +55,6 @@ rwstatus = rw_status.rwstatus_from_exc_map(rwstatus_exception_map)
 rwcalstatus = rwcal_status.rwcalstatus_from_exc_map(rwstatus_exception_map)
 
 
-espec_utils = openstack_drv.OpenstackExtraSpecUtils()
-
 class OpenstackCALOperationFailure(Exception):
     pass
 
@@ -67,6 +70,25 @@ class ImageUploadError(Exception):
     pass
 
 
+class RwcalAccountDriver(object):
+    """
+    Container class per cloud account
+    """
+    def __init__(self, logger, **kwargs):
+        self.log = logger
+        try:
+            self._driver = openstack_drv.OpenstackDriver(logger = self.log, **kwargs)
+        except (KeystoneExceptions.Unauthorized, KeystoneExceptions.AuthorizationFailure,
+                NeutronException.NotFound) as e:
+            raise
+        except Exception as e:
+            self.log.error("RwcalOpenstackPlugin: OpenstackDriver init failed. Exception: %s" %(str(e)))
+            raise
+
+    @property
+    def driver(self):
+        return self._driver
+    
 class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
     """This class implements the CAL VALA methods for openstack."""
 
@@ -77,43 +99,37 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         self._driver_class = openstack_drv.OpenstackDriver
         self.log = logging.getLogger('rwcal.openstack.%s' % RwcalOpenstackPlugin.instance_num)
         self.log.setLevel(logging.DEBUG)
-
         self._rwlog_handler = None
+        self._account_drivers = dict()
         RwcalOpenstackPlugin.instance_num += 1
 
-    @contextlib.contextmanager
     def _use_driver(self, account):
         if self._rwlog_handler is None:
             raise UninitializedPluginError("Must call init() in CAL plugin before use.")
 
-        with rwlogger.rwlog_root_handler(self._rwlog_handler):
-            try:
-                drv = self._driver_class(username            = account.openstack.key,
-                                         password            = account.openstack.secret,
-                                         auth_url            = account.openstack.auth_url,
-                                         tenant_name         = account.openstack.tenant,
-                                         mgmt_network        = account.openstack.mgmt_network,
-                                         cert_validate       = account.openstack.cert_validate,
-                                         user_domain_name    = account.openstack.user_domain,
-                                         project_domain_name = account.openstack.project_domain,
-                                         region              = account.openstack.region)
-            except (KeystoneExceptions.Unauthorized, KeystoneExceptions.AuthorizationFailure,
-                        NeutronException.NotFound) as e:
-                raise
-            except Exception as e:
-                self.log.error("RwcalOpenstackPlugin: OpenstackDriver init failed. Exception: %s" %(str(e)))
-                raise
-
-            yield drv
-
+        if account.name not in self._account_drivers:
+            self.log.debug("Creating OpenstackDriver")
+            kwargs = dict(username = account.openstack.key,
+                          password = account.openstack.secret,
+                          auth_url = account.openstack.auth_url,
+                          project = account.openstack.tenant,
+                          mgmt_network = account.openstack.mgmt_network,
+                          cert_validate = account.openstack.cert_validate,
+                          user_domain = account.openstack.user_domain,
+                          project_domain = account.openstack.project_domain,
+                          region = account.openstack.region)
+            drv = RwcalAccountDriver(self.log, **kwargs)
+            self._account_drivers[account.name] = drv
+            return drv.driver
+        else:
+            return self._account_drivers[account.name].driver
+        
 
     @rwstatus
     def do_init(self, rwlog_ctx):
-        self._rwlog_handler = rwlogger.RwLogger(
-                category="rw-cal-log",
-                subcategory="openstack",
-                log_hdl=rwlog_ctx,
-                )
+        self._rwlog_handler = rwlogger.RwLogger(category="rw-cal-log",
+                                                subcategory="openstack",
+                                                log_hdl=rwlog_ctx,)
         self.log.addHandler(self._rwlog_handler)
         self.log.propagate = False
 
@@ -130,24 +146,24 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             Validation Code and Details String
         """
         status = RwcalYang.CloudConnectionStatus()
+        drv = self._use_driver(account) 
         try:
-            with self._use_driver(account) as drv:
-                drv.validate_account_creds()
-
+            drv.validate_account_creds()
         except KeystoneExceptions.Unauthorized as e:
-            self.log.error("Invalid credentials given for VIM account %s" %account.name)
+            self.log.error("Invalid credentials given for VIM account %s"account.name)
             status.status = "failure"
             status.details = "Invalid Credentials: %s" % str(e)
 
         except KeystoneExceptions.AuthorizationFailure as e:
-            self.log.error("Bad authentication URL given for VIM account %s. Given auth url: %s" % (
-            account.name, account.openstack.auth_url))
+            self.log.error("Bad authentication URL given for VIM account %s. Given auth url: %s",
+                           account.name, account.openstack.auth_url)
             status.status = "failure"
             status.details = "Invalid auth url: %s" % str(e)
 
         except NeutronException.NotFound as e:
-            self.log.error("Given management network %s could not be found for VIM account %s" % (
-                        account.openstack.mgmt_network, account.name))
+            self.log.error("Given management network %s could not be found for VIM account %s",
+                           account.openstack.mgmt_network,
+                           account.name)
             status.status = "failure"
             status.details = "mgmt network does not exist: %s" % str(e)
 
@@ -261,42 +277,39 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             The image id
         """
+        drv = self._use_driver(account)
+        fd = drv.utils.image.create_image_handle(image)
+        kwargs = drv.utils.image.make_image_args(image)
 
         try:
-            # If the use passed in a file descriptor, use that to
-            # upload the image.
-            if image.has_field("fileno"):
-                new_fileno = os.dup(image.fileno)
-                hdl = os.fdopen(new_fileno, 'rb')
-            else:
-                hdl = open(image.location, "rb")
+            # Create Image
+            image_id = drv.glance_image_create(**kwargs)
+            drv.glance_image_upload(image_id, fd)
         except Exception as e:
-            self.log.error("Could not open file for upload. Exception received: %s", str(e))
+            self.log.exception("Exception %s occured during image create", str(e))
             raise
-
-        with hdl as fd:
-            kwargs = {}
-            kwargs['name'] = image.name
-
-            if image.disk_format:
-                kwargs['disk_format'] = image.disk_format
-            if image.container_format:
-                kwargs['container_format'] = image.container_format
-
-            with self._use_driver(account) as drv:
-                # Create Image
-                image_id = drv.glance_image_create(**kwargs)
-                # Upload the Image
-                drv.glance_image_upload(image_id, fd)
-
-                if image.checksum:
-                    stored_image = drv.glance_image_get(image_id)
-                    if stored_image.checksum != image.checksum:
-                        drv.glance_image_delete(image_id=image_id)
-                        raise ImageUploadError(
-                                "image checksum did not match (actual: %s, expected: %s). Deleting." %
-                                (stored_image.checksum, image.checksum)
-                                )
+        finally:
+            fd.close()
+            
+        # Update image properties, if they are provided
+        try:
+            if image.has_field("properties") and image.properties is not None:
+                for key in image.properties:
+                    drv.glance_image_update(image_id, **{key.name: key.property_value})
+        except Exception as e:
+            self.log.exception("Exception %s occured during image update", str(e))
+            raise
+        
+        if image.checksum:
+            try:
+                stored_image = drv.glance_image_get(image_id)
+                if stored_image.checksum != image.checksum:
+                    drv.glance_image_delete(image_id=image_id)
+                    raise ImageUploadError("image checksum did not match (actual: %s, expected: %s). Deleting." %
+                                           (stored_image.checksum, image.checksum))
+            except Exception as e:
+                self.log.exception("Exception %s occured during image checksum verification", str(e))
+                raise
 
         return image_id
 
@@ -308,36 +321,14 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             account - a cloud account
             image_id - id of the image to delete
         """
-        with self._use_driver(account) as drv:
+        drv = self._use_driver(account)
+        try:
             drv.glance_image_delete(image_id=image_id)
+        except Exception as e:
+            self.log.exception("Exception %s occured during image deletion", str(e))
+            raise
 
 
-    @staticmethod
-    def _fill_image_info(img_info):
-        """Create a GI object from image info dictionary
-
-        Converts image information dictionary object returned by openstack
-        driver into Protobuf Gi Object
-
-        Arguments:
-            account - a cloud account
-            img_info - image information dictionary object from openstack
-
-        Returns:
-            The ImageInfoItem
-        """
-        img = RwcalYang.ImageInfoItem()
-        img.name = img_info['name']
-        img.id = img_info['id']
-        img.checksum = img_info['checksum']
-        img.disk_format = img_info['disk_format']
-        img.container_format = img_info['container_format']
-        if img_info['status'] == 'active':
-            img.state = 'active'
-        else:
-            img.state = 'inactive'
-        return img
-
     @rwstatus(ret_on_failure=[[]])
     def do_get_image_list(self, account):
         """Return a list of the names of all available images.
@@ -349,10 +340,14 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             The the list of images in VimResources object
         """
         response = RwcalYang.VimResources()
-        with self._use_driver(account) as drv:
+        drv = self._use_driver(account)
+        try:
             images = drv.glance_image_list()
-        for img in images:
-            response.imageinfo_list.append(RwcalOpenstackPlugin._fill_image_info(img))
+            for img in images:
+                response.imageinfo_list.append(drv.utils.image.parse_cloud_image_info(img))
+        except Exception as e:
+            self.log.exception("Exception %s occured during get-image-list", str(e))
+            raise
         return response
 
     @rwstatus(ret_on_failure=[None])
@@ -366,9 +361,15 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             ImageInfoItem object containing image information.
         """
-        with self._use_driver(account) as drv:
-            image = drv.glance_image_get(image_id)
-        return RwcalOpenstackPlugin._fill_image_info(image)
+        drv = self._use_driver(account)
+        try:
+            image_info = drv.glance_image_get(image_id)
+            image =  drv.utils.image.parse_cloud_image_info(image_info)
+        except Exception as e:
+            self.log.exception("Exception %s occured during get-image", str(e))
+            raise
+        return image
+    
 
     # This is being deprecated. Please do not use for new SW development
     @rwstatus(ret_on_failure=[""])
@@ -382,20 +383,21 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             The image id
         """
+        from warnings import warn
+        warn("This function is deprecated")
         kwargs = {}
         kwargs['name']      = vminfo.vm_name
         kwargs['flavor_id'] = vminfo.flavor_id
         if vminfo.has_field('image_id'):
             kwargs['image_id']  = vminfo.image_id
 
-        with self._use_driver(account) as drv:
-            ### If floating_ip is required and we don't have one, better fail before any further allocation
-            pool_name = None
-            floating_ip = False
-            if vminfo.has_field('allocate_public_address') and vminfo.allocate_public_address:
-                if account.openstack.has_field('floating_ip_pool'):
-                    pool_name = account.openstack.floating_ip_pool
-                floating_ip = True
+        ### If floating_ip is required and we don't have one, better fail before any further allocation
+        pool_name = None
+        floating_ip = False
+        if vminfo.has_field('allocate_public_address') and vminfo.allocate_public_address:
+            if account.openstack.has_field('floating_ip_pool'):
+                pool_name = account.openstack.floating_ip_pool
+            floating_ip = True
 
         if vminfo.has_field('cloud_init') and vminfo.cloud_init.has_field('userdata'):
             kwargs['userdata']  = vminfo.cloud_init.userdata
@@ -435,10 +437,10 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         else:
             kwargs['scheduler_hints'] = None
 
-        with self._use_driver(account) as drv:
-            vm_id = drv.nova_server_create(**kwargs)
-            if floating_ip:
-                self.prepare_vdu_on_boot(account, vm_id, floating_ip)
+        drv = self._use_driver(account)
+        vm_id = drv.nova_server_create(**kwargs)
+        if floating_ip:
+            self.prepare_vdu_on_boot(account, vm_id, floating_ip)
 
         return vm_id
 
@@ -450,8 +452,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             account - a cloud account
             vm_id - an id of the VM
         """
-        with self._use_driver(account) as drv:
-            drv.nova_server_start(vm_id)
+        drv = self._use_driver(account)
+        drv.nova_server_start(vm_id)
 
     @rwstatus
     def do_stop_vm(self, account, vm_id):
@@ -461,8 +463,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             account - a cloud account
             vm_id - an id of the VM
         """
-        with self._use_driver(account) as drv:
-            drv.nova_server_stop(vm_id)
+        drv = self._use_driver(account)
+        drv.nova_server_stop(vm_id)
 
     @rwstatus
     def do_delete_vm(self, account, vm_id):
@@ -472,8 +474,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             account - a cloud account
             vm_id - an id of the VM
         """
-        with self._use_driver(account) as drv:
-            drv.nova_server_delete(vm_id)
+        drv = self._use_driver(account)
+        drv.nova_server_delete(vm_id)
 
     @rwstatus
     def do_reboot_vm(self, account, vm_id):
@@ -483,8 +485,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             account - a cloud account
             vm_id - an id of the VM
         """
-        with self._use_driver(account) as drv:
-            drv.nova_server_reboot(vm_id)
+        drv = self._use_driver(account)
+        drv.nova_server_reboot(vm_id)
 
     @staticmethod
     def _fill_vm_info(vm_info, mgmt_network):
@@ -510,7 +512,7 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             if network_info:
                 if network_name == mgmt_network:
                     vm.public_ip = next((item['addr']
-                                            for item in network_info
+                                         for item in network_info
                                             if item['OS-EXT-IPS:type'] == 'floating'),
                                         network_info[0]['addr'])
                     vm.management_ip = network_info[0]['addr']
@@ -548,8 +550,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             List containing VM information
         """
         response = RwcalYang.VimResources()
-        with self._use_driver(account) as drv:
-            vms = drv.nova_server_list()
+        drv = self._use_driver(account)
+        vms = drv.nova_server_list()
         for vm in vms:
             response.vminfo_list.append(RwcalOpenstackPlugin._fill_vm_info(vm, account.openstack.mgmt_network))
         return response
@@ -565,159 +567,10 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             VM information
         """
-        with self._use_driver(account) as drv:
-            vm = drv.nova_server_get(id)
+        drv = self._use_driver(account)
+        vm = drv.nova_server_get(id)
         return RwcalOpenstackPlugin._fill_vm_info(vm, account.openstack.mgmt_network)
 
-    @staticmethod
-    def _get_guest_epa_specs(guest_epa):
-        """
-        Returns EPA Specs dictionary for guest_epa attributes
-        """
-        epa_specs = {}
-        if guest_epa.has_field('mempage_size'):
-            mempage_size = espec_utils.guest.mano_to_extra_spec_mempage_size(guest_epa.mempage_size)
-            if mempage_size is not None:
-                epa_specs['hw:mem_page_size'] = mempage_size
-
-        if guest_epa.has_field('cpu_pinning_policy'):
-            cpu_pinning_policy = espec_utils.guest.mano_to_extra_spec_cpu_pinning_policy(guest_epa.cpu_pinning_policy)
-            if cpu_pinning_policy is not None:
-                epa_specs['hw:cpu_policy'] = cpu_pinning_policy
-
-        if guest_epa.has_field('cpu_thread_pinning_policy'):
-            cpu_thread_pinning_policy = espec_utils.guest.mano_to_extra_spec_cpu_thread_pinning_policy(guest_epa.cpu_thread_pinning_policy)
-            if cpu_thread_pinning_policy is None:
-                epa_specs['hw:cpu_threads_policy'] = cpu_thread_pinning_policy
-
-        if guest_epa.has_field('trusted_execution'):
-            trusted_execution = espec_utils.guest.mano_to_extra_spec_trusted_execution(guest_epa.trusted_execution)
-            if trusted_execution is not None:
-                epa_specs['trust:trusted_host'] = trusted_execution
-
-        if guest_epa.has_field('numa_node_policy'):
-            if guest_epa.numa_node_policy.has_field('node_cnt'):
-                numa_node_count = espec_utils.guest.mano_to_extra_spec_numa_node_count(guest_epa.numa_node_policy.node_cnt)
-                if numa_node_count is not None:
-                    epa_specs['hw:numa_nodes'] = numa_node_count
-
-            if guest_epa.numa_node_policy.has_field('mem_policy'):
-                numa_memory_policy = espec_utils.guest.mano_to_extra_spec_numa_memory_policy(guest_epa.numa_node_policy.mem_policy)
-                if numa_memory_policy is not None:
-                    epa_specs['hw:numa_mempolicy'] = numa_memory_policy
-
-            if guest_epa.numa_node_policy.has_field('node'):
-                for node in guest_epa.numa_node_policy.node:
-                    if node.has_field('vcpu') and node.vcpu:
-                        epa_specs['hw:numa_cpus.'+str(node.id)] = ','.join([str(j.id) for j in node.vcpu])
-                    if node.memory_mb:
-                        epa_specs['hw:numa_mem.'+str(node.id)] = str(node.memory_mb)
-
-        if guest_epa.has_field('pcie_device'):
-            pci_devices = []
-            for device in guest_epa.pcie_device:
-                pci_devices.append(device.device_id +':'+str(device.count))
-            epa_specs['pci_passthrough:alias'] = ','.join(pci_devices)
-
-        return epa_specs
-
-    @staticmethod
-    def _get_host_epa_specs(host_epa):
-        """
-        Returns EPA Specs dictionary for host_epa attributes
-        """
-
-        epa_specs = {}
-
-        if host_epa.has_field('cpu_model'):
-            cpu_model = espec_utils.host.mano_to_extra_spec_cpu_model(host_epa.cpu_model)
-            if cpu_model is not None:
-                epa_specs['capabilities:cpu_info:model'] = cpu_model
-
-        if host_epa.has_field('cpu_arch'):
-            cpu_arch = espec_utils.host.mano_to_extra_spec_cpu_arch(host_epa.cpu_arch)
-            if cpu_arch is not None:
-                epa_specs['capabilities:cpu_info:arch'] = cpu_arch
-
-        if host_epa.has_field('cpu_vendor'):
-            cpu_vendor = espec_utils.host.mano_to_extra_spec_cpu_vendor(host_epa.cpu_vendor)
-            if cpu_vendor is not None:
-                epa_specs['capabilities:cpu_info:vendor'] = cpu_vendor
-
-        if host_epa.has_field('cpu_socket_count'):
-            cpu_socket_count = espec_utils.host.mano_to_extra_spec_cpu_socket_count(host_epa.cpu_socket_count)
-            if cpu_socket_count is not None:
-                epa_specs['capabilities:cpu_info:topology:sockets'] = cpu_socket_count
-
-        if host_epa.has_field('cpu_core_count'):
-            cpu_core_count = espec_utils.host.mano_to_extra_spec_cpu_core_count(host_epa.cpu_core_count)
-            if cpu_core_count is not None:
-                epa_specs['capabilities:cpu_info:topology:cores'] = cpu_core_count
-
-        if host_epa.has_field('cpu_core_thread_count'):
-            cpu_core_thread_count = espec_utils.host.mano_to_extra_spec_cpu_core_thread_count(host_epa.cpu_core_thread_count)
-            if cpu_core_thread_count is not None:
-                epa_specs['capabilities:cpu_info:topology:threads'] = cpu_core_thread_count
-
-        if host_epa.has_field('cpu_feature'):
-            cpu_features = []
-            espec_cpu_features = []
-            for feature in host_epa.cpu_feature:
-                cpu_features.append(feature.feature)
-            espec_cpu_features = espec_utils.host.mano_to_extra_spec_cpu_features(cpu_features)
-            if espec_cpu_features is not None:
-                epa_specs['capabilities:cpu_info:features'] = espec_cpu_features
-        return epa_specs
-
-    @staticmethod
-    def _get_hypervisor_epa_specs(guest_epa):
-        """
-        Returns EPA Specs dictionary for hypervisor_epa attributes
-        """
-        hypervisor_epa = {}
-        return hypervisor_epa
-
-    @staticmethod
-    def _get_vswitch_epa_specs(guest_epa):
-        """
-        Returns EPA Specs dictionary for vswitch_epa attributes
-        """
-        vswitch_epa = {}
-        return vswitch_epa
-
-    @staticmethod
-    def _get_host_aggregate_epa_specs(host_aggregate):
-        """
-        Returns EPA Specs dictionary for host aggregates
-        """
-        epa_specs = {}
-        for aggregate in host_aggregate:
-            epa_specs['aggregate_instance_extra_specs:'+aggregate.metadata_key] = aggregate.metadata_value
-
-        return epa_specs
-
-    @staticmethod
-    def _get_epa_specs(flavor):
-        """
-        Returns epa_specs dictionary based on flavor information
-        """
-        epa_specs = {}
-        if flavor.has_field('guest_epa'):
-            guest_epa = RwcalOpenstackPlugin._get_guest_epa_specs(flavor.guest_epa)
-            epa_specs.update(guest_epa)
-        if flavor.has_field('host_epa'):
-            host_epa = RwcalOpenstackPlugin._get_host_epa_specs(flavor.host_epa)
-            epa_specs.update(host_epa)
-        if flavor.has_field('hypervisor_epa'):
-            hypervisor_epa = RwcalOpenstackPlugin._get_hypervisor_epa_specs(flavor.hypervisor_epa)
-            epa_specs.update(hypervisor_epa)
-        if flavor.has_field('vswitch_epa'):
-            vswitch_epa = RwcalOpenstackPlugin._get_vswitch_epa_specs(flavor.vswitch_epa)
-            epa_specs.update(vswitch_epa)
-        if flavor.has_field('host_aggregate'):
-            host_aggregate = RwcalOpenstackPlugin._get_host_aggregate_epa_specs(flavor.host_aggregate)
-            epa_specs.update(host_aggregate)
-        return epa_specs
 
     @rwstatus(ret_on_failure=[""])
     def do_create_flavor(self, account, flavor):
@@ -730,14 +583,13 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             flavor id
         """
-        epa_specs = RwcalOpenstackPlugin._get_epa_specs(flavor)
-        with self._use_driver(account) as drv:
-            return drv.nova_flavor_create(name      = flavor.name,
-                                          ram       = flavor.vm_flavor.memory_mb,
-                                          vcpus     = flavor.vm_flavor.vcpu_count,
-                                          disk      = flavor.vm_flavor.storage_gb,
-                                          epa_specs = epa_specs)
-
+        drv = self._use_driver(account)
+        return drv.nova_flavor_create(name      = flavor.name,
+                                      ram       = flavor.vm_flavor.memory_mb,
+                                      vcpus     = flavor.vm_flavor.vcpu_count,
+                                      disk      = flavor.vm_flavor.storage_gb,
+                                      epa_specs = drv.utils.flavor.get_extra_specs(flavor))
+    
 
     @rwstatus
     def do_delete_flavor(self, account, flavor_id):
@@ -747,148 +599,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             account - a cloud account
             flavor_id - id flavor of the VM
         """
-        with self._use_driver(account) as drv:
-            drv.nova_flavor_delete(flavor_id)
-
-    @staticmethod
-    def _fill_epa_attributes(flavor, flavor_info):
-        """Helper function to populate the EPA attributes
-
-        Arguments:
-              flavor     : Object with EPA attributes
-              flavor_info: A dictionary of flavor_info received from openstack
-        Returns:
-              None
-        """
-        getattr(flavor, 'vm_flavor').vcpu_count  = flavor_info['vcpus']
-        getattr(flavor, 'vm_flavor').memory_mb   = flavor_info['ram']
-        getattr(flavor, 'vm_flavor').storage_gb  = flavor_info['disk']
-
-        ### If extra_specs in flavor_info
-        if not 'extra_specs' in flavor_info:
-            return
-
-        for attr in flavor_info['extra_specs']:
-            if attr == 'hw:cpu_policy':
-                cpu_pinning_policy = espec_utils.guest.extra_spec_to_mano_cpu_pinning_policy(flavor_info['extra_specs']['hw:cpu_policy'])
-                if cpu_pinning_policy is not None:
-                    getattr(flavor, 'guest_epa').cpu_pinning_policy = cpu_pinning_policy
-
-            elif attr == 'hw:cpu_threads_policy':
-                cpu_thread_pinning_policy = espec_utils.guest.extra_spec_to_mano_cpu_thread_pinning_policy(flavor_info['extra_specs']['hw:cpu_threads_policy'])
-                if cpu_thread_pinning_policy is not None:
-                    getattr(flavor, 'guest_epa').cpu_thread_pinning_policy = cpu_thread_pinning_policy
-
-            elif attr == 'hw:mem_page_size':
-                mempage_size = espec_utils.guest.extra_spec_to_mano_mempage_size(flavor_info['extra_specs']['hw:mem_page_size'])
-                if mempage_size is not None:
-                    getattr(flavor, 'guest_epa').mempage_size = mempage_size
-
-
-            elif attr == 'hw:numa_nodes':
-                numa_node_count = espec_utils.guest.extra_specs_to_mano_numa_node_count(flavor_info['extra_specs']['hw:numa_nodes'])
-                if numa_node_count is not None:
-                    getattr(flavor,'guest_epa').numa_node_policy.node_cnt = numa_node_count
-
-            elif attr.startswith('hw:numa_cpus.'):
-                node_id = attr.split('.')[1]
-                nodes = [ n for n in flavor.guest_epa.numa_node_policy.node if n.id == int(node_id) ]
-                if nodes:
-                    numa_node = nodes[0]
-                else:
-                    numa_node = getattr(flavor,'guest_epa').numa_node_policy.node.add()
-                    numa_node.id = int(node_id)
-
-                for x in flavor_info['extra_specs'][attr].split(','):
-                   numa_node_vcpu = numa_node.vcpu.add()
-                   numa_node_vcpu.id = int(x)
-
-            elif attr.startswith('hw:numa_mem.'):
-                node_id = attr.split('.')[1]
-                nodes = [ n for n in flavor.guest_epa.numa_node_policy.node if n.id == int(node_id) ]
-                if nodes:
-                    numa_node = nodes[0]
-                else:
-                    numa_node = getattr(flavor,'guest_epa').numa_node_policy.node.add()
-                    numa_node.id = int(node_id)
-
-                numa_node.memory_mb =  int(flavor_info['extra_specs'][attr])
-
-            elif attr == 'hw:numa_mempolicy':
-                numa_memory_policy = espec_utils.guest.extra_to_mano_spec_numa_memory_policy(flavor_info['extra_specs']['hw:numa_mempolicy'])
-                if numa_memory_policy is not None:
-                    getattr(flavor,'guest_epa').numa_node_policy.mem_policy = numa_memory_policy
-
-            elif attr == 'trust:trusted_host':
-                trusted_execution = espec_utils.guest.extra_spec_to_mano_trusted_execution(flavor_info['extra_specs']['trust:trusted_host'])
-                if trusted_execution is not None:
-                    getattr(flavor,'guest_epa').trusted_execution = trusted_execution
-
-            elif attr == 'pci_passthrough:alias':
-                device_types = flavor_info['extra_specs']['pci_passthrough:alias']
-                for device in device_types.split(','):
-                    dev = getattr(flavor,'guest_epa').pcie_device.add()
-                    dev.device_id = device.split(':')[0]
-                    dev.count = int(device.split(':')[1])
-
-            elif attr == 'capabilities:cpu_info:model':
-                cpu_model = espec_utils.host.extra_specs_to_mano_cpu_model(flavor_info['extra_specs']['capabilities:cpu_info:model'])
-                if cpu_model is not None:
-                    getattr(flavor, 'host_epa').cpu_model = cpu_model
-
-            elif attr == 'capabilities:cpu_info:arch':
-                cpu_arch = espec_utils.host.extra_specs_to_mano_cpu_arch(flavor_info['extra_specs']['capabilities:cpu_info:arch'])
-                if cpu_arch is not None:
-                    getattr(flavor, 'host_epa').cpu_arch = cpu_arch
-
-            elif attr == 'capabilities:cpu_info:vendor':
-                cpu_vendor = espec_utils.host.extra_spec_to_mano_cpu_vendor(flavor_info['extra_specs']['capabilities:cpu_info:vendor'])
-                if cpu_vendor is not None:
-                    getattr(flavor, 'host_epa').cpu_vendor = cpu_vendor
-
-            elif attr == 'capabilities:cpu_info:topology:sockets':
-                cpu_sockets = espec_utils.host.extra_spec_to_mano_cpu_socket_count(flavor_info['extra_specs']['capabilities:cpu_info:topology:sockets'])
-                if cpu_sockets is not None:
-                    getattr(flavor, 'host_epa').cpu_socket_count = cpu_sockets
-
-            elif attr == 'capabilities:cpu_info:topology:cores':
-                cpu_cores = espec_utils.host.extra_spec_to_mano_cpu_core_count(flavor_info['extra_specs']['capabilities:cpu_info:topology:cores'])
-                if cpu_cores is not None:
-                    getattr(flavor, 'host_epa').cpu_core_count = cpu_cores
-
-            elif attr == 'capabilities:cpu_info:topology:threads':
-                cpu_threads = espec_utils.host.extra_spec_to_mano_cpu_core_thread_count(flavor_info['extra_specs']['capabilities:cpu_info:topology:threads'])
-                if cpu_threads is not None:
-                    getattr(flavor, 'host_epa').cpu_core_thread_count = cpu_threads
-
-            elif attr == 'capabilities:cpu_info:features':
-                cpu_features = espec_utils.host.extra_spec_to_mano_cpu_features(flavor_info['extra_specs']['capabilities:cpu_info:features'])
-                if cpu_features is not None:
-                    for feature in cpu_features:
-                        getattr(flavor, 'host_epa').cpu_feature.append(feature)
-            elif attr.startswith('aggregate_instance_extra_specs:'):
-                    aggregate = getattr(flavor, 'host_aggregate').add()
-                    aggregate.metadata_key = ":".join(attr.split(':')[1::])
-                    aggregate.metadata_value = flavor_info['extra_specs'][attr]
-
-    @staticmethod
-    def _fill_flavor_info(flavor_info):
-        """Create a GI object from flavor info dictionary
-
-        Converts Flavor information dictionary object returned by openstack
-        driver into Protobuf Gi Object
-
-        Arguments:
-            flavor_info: Flavor information from openstack
-
-        Returns:
-             Object of class FlavorInfoItem
-        """
-        flavor = RwcalYang.FlavorInfoItem()
-        flavor.name                       = flavor_info['name']
-        flavor.id                         = flavor_info['id']
-        RwcalOpenstackPlugin._fill_epa_attributes(flavor, flavor_info)
-        return flavor
+        drv = self._use_driver(account)
+        drv.nova_flavor_delete(flavor_id)
 
 
     @rwstatus(ret_on_failure=[[]])
@@ -902,10 +614,10 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             List of flavors
         """
         response = RwcalYang.VimResources()
-        with self._use_driver(account) as drv:
-            flavors = drv.nova_flavor_list()
+        drv = self._use_driver(account)
+        flavors = drv.nova_flavor_list()
         for flv in flavors:
-            response.flavorinfo_list.append(RwcalOpenstackPlugin._fill_flavor_info(flv))
+            response.flavorinfo_list.append(drv.utils.flavor.parse_flavor_info(flv))
         return response
 
     @rwstatus(ret_on_failure=[None])
@@ -919,9 +631,9 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             Flavor info item
         """
-        with self._use_driver(account) as drv:
-            flavor = drv.nova_flavor_get(id)
-        return RwcalOpenstackPlugin._fill_flavor_info(flavor)
+        drv = self._use_driver(account)
+        flavor = drv.nova_flavor_get(id)
+        return drv.utils.flavor.parse_flavor_info(flavor)
 
 
     def _fill_network_info(self, network_info, account):
@@ -949,8 +661,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
 
         if 'subnets' in network_info and network_info['subnets']:
             subnet_id = network_info['subnets'][0]
-            with self._use_driver(account) as drv:
-                subnet = drv.neutron_subnet_get(subnet_id)
+            drv = self._use_driver(account)
+            subnet = drv.neutron_subnet_get(subnet_id)
             network.subnet = subnet['cidr']
         return network
 
@@ -965,8 +677,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             List of networks
         """
         response = RwcalYang.VimResources()
-        with self._use_driver(account) as drv:
-            networks = drv.neutron_network_list()
+        drv = self._use_driver(account)
+        networks = drv.neutron_network_list()
         for network in networks:
             response.networkinfo_list.append(self._fill_network_info(network, account))
         return response
@@ -982,8 +694,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             Network info item
         """
-        with self._use_driver(account) as drv:
-            network = drv.neutron_network_get(id)
+        drv = self._use_driver(account)
+        network = drv.neutron_network_get(id)
         return self._fill_network_info(network, account)
 
     @rwstatus(ret_on_failure=[""])
@@ -997,6 +709,9 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             Network id
         """
+        from warnings import warn
+        warn("This function is deprecated")
+
         kwargs = {}
         kwargs['name']            = network.network_name
         kwargs['admin_state_up']  = True
@@ -1011,10 +726,10 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             if network.provider_network.has_field('segmentation_id'):
                 kwargs['segmentation_id'] = network.provider_network.segmentation_id
 
-        with self._use_driver(account) as drv:
-            network_id = drv.neutron_network_create(**kwargs)
-            drv.neutron_subnet_create(network_id = network_id,
-                                      cidr = network.subnet)
+        drv = self._use_driver(account)
+        network_id = drv.neutron_network_create(**kwargs)
+        drv.neutron_subnet_create(network_id = network_id,
+                                  cidr = network.subnet)
         return network_id
 
     @rwstatus
@@ -1025,8 +740,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             account - a cloud account
             network_id - an id for the network
         """
-        with self._use_driver(account) as drv:
-            drv.neutron_network_delete(network_id)
+        drv = self._use_driver(account)
+        drv.neutron_network_delete(network_id)
 
     @staticmethod
     def _fill_port_info(port_info):
@@ -1064,9 +779,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             Port info item
         """
-        with self._use_driver(account) as drv:
-            port = drv.neutron_port_get(port_id)
-
+        drv = self._use_driver(account)
+        port = drv.neutron_port_get(port_id)
         return RwcalOpenstackPlugin._fill_port_info(port)
 
     @rwstatus(ret_on_failure=[[]])
@@ -1080,8 +794,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             Port info list
         """
         response = RwcalYang.VimResources()
-        with self._use_driver(account) as drv:
-            ports = drv.neutron_port_list(*{})
+        drv = self._use_driver(account)
+        ports = drv.neutron_port_list(*{})
         for port in ports:
             response.portinfo_list.append(RwcalOpenstackPlugin._fill_port_info(port))
         return response
@@ -1097,6 +811,9 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             Port id
         """
+        from warnings import warn
+        warn("This function is deprecated")
+
         kwargs = {}
         kwargs['name'] = port.port_name
         kwargs['network_id'] = port.network_id
@@ -1108,8 +825,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         else:
             kwargs['port_type'] = "normal"
 
-        with self._use_driver(account) as drv:
-            return drv.neutron_port_create(**kwargs)
+        drv = self._use_driver(account)
+        return drv.neutron_port_create(**kwargs)
 
     @rwstatus
     def do_delete_port(self, account, port_id):
@@ -1119,8 +836,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             account - a cloud account
             port_id - an id for port
         """
-        with self._use_driver(account) as drv:
-            drv.neutron_port_delete(port_id)
+        drv = self._use_driver(account)
+        drv.neutron_port_delete(port_id)
 
     @rwstatus(ret_on_failure=[""])
     def do_add_host(self, account, host):
@@ -1170,162 +887,6 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         """
         raise NotImplementedError
 
-    @staticmethod
-    def _fill_connection_point_info(c_point, port_info):
-        """Create a GI object for RwcalYang.VDUInfoParams_ConnectionPoints()
-
-        Converts Port information dictionary object returned by openstack
-        driver into Protobuf Gi Object
-
-        Arguments:
-            port_info - Port information from openstack
-        Returns:
-            Protobuf Gi object for RwcalYang.VDUInfoParams_ConnectionPoints
-        """
-        c_point.name = port_info['name']
-        c_point.connection_point_id = port_info['id']
-        if ('fixed_ips' in port_info) and (len(port_info['fixed_ips']) >= 1):
-            if 'ip_address' in port_info['fixed_ips'][0]:
-                c_point.ip_address = port_info['fixed_ips'][0]['ip_address']
-        if 'mac_address' in port_info :
-            c_point.mac_addr = port_info['mac_address']
-        if port_info['status'] == 'ACTIVE':
-            c_point.state = 'active'
-        else:
-            c_point.state = 'inactive'
-        if 'network_id' in port_info:
-            c_point.virtual_link_id = port_info['network_id']
-        if ('device_id' in port_info) and (port_info['device_id']):
-            c_point.vdu_id = port_info['device_id']
-
-    @staticmethod
-    def _fill_virtual_link_info(network_info, port_list, subnet):
-        """Create a GI object for VirtualLinkInfoParams
-
-        Converts Network and Port information dictionary object
-        returned by openstack driver into Protobuf Gi Object
-
-        Arguments:
-            network_info - Network information from openstack
-            port_list - A list of port information from openstack
-            subnet: Subnet information from openstack
-        Returns:
-            Protobuf Gi object for VirtualLinkInfoParams
-        """
-        link = RwcalYang.VirtualLinkInfoParams()
-        link.name  = network_info['name']
-        if network_info['status'] == 'ACTIVE':
-            link.state = 'active'
-        else:
-            link.state = 'inactive'
-        link.virtual_link_id = network_info['id']
-        for port in port_list:
-            if port['device_owner'] == 'compute:None':
-                c_point = link.connection_points.add()
-                RwcalOpenstackPlugin._fill_connection_point_info(c_point, port)
-
-        if subnet != None:
-            link.subnet = subnet['cidr']
-
-        if ('provider:network_type' in network_info) and (network_info['provider:network_type'] != None):
-            link.provider_network.overlay_type = network_info['provider:network_type'].upper()
-        if ('provider:segmentation_id' in network_info) and (network_info['provider:segmentation_id']):
-            link.provider_network.segmentation_id = network_info['provider:segmentation_id']
-        if ('provider:physical_network' in network_info) and (network_info['provider:physical_network']):
-            link.provider_network.physical_network = network_info['provider:physical_network'].upper()
-
-        return link
-
-    @staticmethod
-    def _fill_vdu_info(drv, vm_info, flavor_info, mgmt_network, port_list, server_group, volume_list = None):
-        """Create a GI object for VDUInfoParams
-
-        Converts VM information dictionary object returned by openstack
-        driver into Protobuf Gi Object
-
-        Arguments:
-            vm_info - VM information from openstack
-            flavor_info - VM Flavor information from openstack
-            mgmt_network - Management network
-            port_list - A list of port information from openstack
-            server_group - A list (with one element or empty list) of server group to which this VM belongs
-        Returns:
-            Protobuf Gi object for VDUInfoParams
-        """
-        vdu = RwcalYang.VDUInfoParams()
-        vdu.name = vm_info['name']
-        vdu.vdu_id = vm_info['id']
-        for network_name, network_info in vm_info['addresses'].items():
-            if network_info and network_name == mgmt_network:
-                for interface in network_info:
-                    if 'OS-EXT-IPS:type' in interface:
-                        if interface['OS-EXT-IPS:type'] == 'fixed':
-                            vdu.management_ip = interface['addr']
-                        elif interface['OS-EXT-IPS:type'] == 'floating':
-                            vdu.public_ip = interface['addr']
-
-        # Look for any metadata
-#        for key, value in vm_info['metadata'].items():
-#            if key == 'node_id':
-#                vdu.node_id = value
-#            else:
-#                custommetadata = vdu.supplemental_boot_data.custom_meta_data.add()
-#                custommetadata.name = key
-#                custommetadata.value = str(value)
-
-        # Look for config_drive
-        if ('config_drive' in vm_info):
-            vdu.supplemental_boot_data.boot_data_drive = vm_info['config_drive']
-        if ('image' in vm_info) and ('id' in vm_info['image']):
-            vdu.image_id = vm_info['image']['id']
-        if ('flavor' in vm_info) and ('id' in vm_info['flavor']):
-            vdu.flavor_id = vm_info['flavor']['id']
-
-        if vm_info['status'] == 'ACTIVE':
-            vdu.state = 'active'
-        elif vm_info['status'] == 'ERROR':
-            vdu.state = 'failed'
-        else:
-            vdu.state = 'inactive'
-
-        if 'availability_zone' in vm_info:
-            vdu.availability_zone = vm_info['availability_zone']
-
-        if server_group:
-            vdu.server_group.name = server_group[0]
-
-        vdu.cloud_type  = 'openstack'
-        # Fill the port information
-        for port in port_list:
-            c_point = vdu.connection_points.add()
-            RwcalOpenstackPlugin._fill_connection_point_info(c_point, port)
-
-        if flavor_info is not None:
-            RwcalOpenstackPlugin._fill_epa_attributes(vdu, flavor_info)
-
-        # Fill the volume information
-        if volume_list is not None:
-            for os_volume in volume_list:
-                volr = vdu.volumes.add()
-                try:
-                   " Device name is of format /dev/vda"
-                   vol_name = (os_volume['device']).split('/')[2]
-                except:
-                   continue
-                volr.name = vol_name
-                volr.volume_id = os_volume['volumeId']
-                try:
-                   vol_details = drv.cinder_volume_get(volr.volume_id)
-                except:
-                   continue
-                if vol_details is None:
-                   continue
-                for key, value in vol_details.metadata.items():
-                      volmd = volr.custom_meta_data.add()
-                      volmd.name = key
-                      volmd.value = value
-
-        return vdu
 
     @rwcalstatus(ret_on_failure=[""])
     def do_create_virtual_link(self, account, link_params):
@@ -1336,73 +897,19 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             link_params - information that defines the type of VDU to create
 
         Returns:
-            The vdu_id
+            A kwargs dictionary for glance operation
         """
-        kwargs = {}
-        kwargs['name']            = link_params.name
-        kwargs['admin_state_up']  = True
-        kwargs['external_router'] = False
-        kwargs['shared']          = False
-
-        if link_params.has_field('provider_network'):
-            if link_params.provider_network.has_field('physical_network'):
-                kwargs['physical_network'] = link_params.provider_network.physical_network
-            if link_params.provider_network.has_field('overlay_type'):
-                kwargs['network_type'] = link_params.provider_network.overlay_type.lower()
-            if link_params.provider_network.has_field('segmentation_id'):
-                kwargs['segmentation_id'] = link_params.provider_network.segmentation_id
-
-
-        with self._use_driver(account) as drv:
-            try:
-                network_id = drv.neutron_network_create(**kwargs)
-            except Exception as e:
-                self.log.error("Encountered exceptions during network creation. Exception: %s", str(e))
-                raise
-
-            kwargs = {'network_id' : network_id,
-                      'dhcp_params': {'enable_dhcp': True},
-                      'gateway_ip' : None,}
-
-            if link_params.ip_profile_params.has_field('ip_version'):
-                kwargs['ip_version'] = 6 if link_params.ip_profile_params.ip_version == 'ipv6' else 4
-            else:
-                kwargs['ip_version'] = 4
-
-            if link_params.ip_profile_params.has_field('subnet_address'):
-                kwargs['cidr'] = link_params.ip_profile_params.subnet_address
-            elif link_params.ip_profile_params.has_field('subnet_prefix_pool'):
-                subnet_pool = drv.netruon_subnetpool_by_name(link_params.ip_profile_params.subnet_prefix_pool)
-                if subnet_pool is None:
-                    self.log.error("Could not find subnet pool with name :%s to be used for network: %s",
-                                   link_params.ip_profile_params.subnet_prefix_pool,
-                                   link_params.name)
-                    raise NeutronException.NotFound("SubnetPool with name %s not found"%(link_params.ip_profile_params.subnet_prefix_pool))
-
-                kwargs['subnetpool_id'] = subnet_pool['id']
-            elif link_params.has_field('subnet'):
-                kwargs['cidr'] = link_params.subnet
-            else:
-                assert 0, "No IP Prefix or Pool name specified"
-
-            if link_params.ip_profile_params.has_field('dhcp_params'):
-                if link_params.ip_profile_params.dhcp_params.has_field('enabled'):
-                    kwargs['dhcp_params']['enable_dhcp'] = link_params.ip_profile_params.dhcp_params.enabled
-                if link_params.ip_profile_params.dhcp_params.has_field('start_address'):
-                    kwargs['dhcp_params']['start_address']  = link_params.ip_profile_params.dhcp_params.start_address
-                if link_params.ip_profile_params.dhcp_params.has_field('count'):
-                    kwargs['dhcp_params']['count']  = link_params.ip_profile_params.dhcp_params.count
-
-            if link_params.ip_profile_params.has_field('dns_server'):
-                kwargs['dns_server'] = []
-                for server in link_params.ip_profile_params.dns_server:
-                    kwargs['dns_server'].append(server.address)
-
-            if link_params.ip_profile_params.has_field('gateway_address'):
-                kwargs['gateway_ip'] = link_params.ip_profile_params.gateway_address
-
-            drv.neutron_subnet_create(**kwargs)
+        
+        drv = self._use_driver(account)
+        try:
+            kwargs = drv.utils.network.make_virtual_link_args(link_params)
+            network_id = drv.neutron_network_create(**kwargs)
+        except Exception as e:
+            self.log.error("Encountered exceptions during network creation. Exception: %s", str(e))
+            raise
 
+        kwargs = drv.utils.network.make_subnet_args(link_params, network_id)
+        drv.neutron_subnet_create(**kwargs)
         return network_id
 
 
@@ -1417,17 +924,16 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             None
         """
-        if not link_id:
-            self.log.error("Empty link_id during the virtual link deletion")
-            raise Exception("Empty link_id during the virtual link deletion")
-
-        with self._use_driver(account) as drv:
+        drv = self._use_driver(account)
+        try:
             port_list = drv.neutron_port_list(**{'network_id': link_id})
-
-        for port in port_list:
-            if ((port['device_owner'] == 'compute:None') or (port['device_owner'] == '')):
-                self.do_delete_port(account, port['id'], no_rwstatus=True)
-        self.do_delete_network(account, link_id, no_rwstatus=True)
+            for port in port_list:
+                if ((port['device_owner'] == 'compute:None') or (port['device_owner'] == '')):
+                    self.do_delete_port(account, port['id'], no_rwstatus=True)
+            self.do_delete_network(account, link_id, no_rwstatus=True)
+        except Exception as e:
+            self.log.exception("Exception %s occured during virtual-link deletion", str(e))
+            raise
 
     @rwstatus(ret_on_failure=[None])
     def do_get_virtual_link(self, account, link_id):
@@ -1440,22 +946,20 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             Object of type RwcalYang.VirtualLinkInfoParams
         """
-        if not link_id:
-            self.log.error("Empty link_id during the virtual link get request")
-            raise Exception("Empty link_id during the virtual link get request")
-
-        with self._use_driver(account) as drv:
+        drv = self._use_driver(account)
+        try:
             network = drv.neutron_network_get(link_id)
             if network:
                 port_list = drv.neutron_port_list(**{'network_id': network['id']})
-                if 'subnets' in network:
+                if 'subnets' in network and network['subnets']:
                     subnet = drv.neutron_subnet_get(network['subnets'][0])
                 else:
                     subnet = None
-                virtual_link = RwcalOpenstackPlugin._fill_virtual_link_info(network, port_list, subnet)
-            else:
-                virtual_link = None
-            return virtual_link
+                virtual_link = drv.utils.network.parse_cloud_virtual_link_info(network, port_list, subnet)
+        except Exception as e:
+            self.log.exception("Exception %s occured during virtual-link-get", str(e))
+            raise
+        return virtual_link
 
     @rwstatus(ret_on_failure=[None])
     def do_get_virtual_link_list(self, account):
@@ -1468,586 +972,23 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             A list of objects of type RwcalYang.VirtualLinkInfoParams
         """
         vnf_resources = RwcalYang.VNFResources()
-        with self._use_driver(account) as drv:
+        drv =  self._use_driver(account)
+        try:
             networks = drv.neutron_network_list()
             for network in networks:
                 port_list = drv.neutron_port_list(**{'network_id': network['id']})
-                if ('subnets' in network) and (network['subnets']):
+                if 'subnets' in network and network['subnets']:
                     subnet = drv.neutron_subnet_get(network['subnets'][0])
                 else:
                     subnet = None
-                virtual_link = RwcalOpenstackPlugin._fill_virtual_link_info(network, port_list, subnet)
+                virtual_link = drv.utils.network.parse_cloud_virtual_link_info(network, port_list, subnet)
                 vnf_resources.virtual_link_info_list.append(virtual_link)
-            return vnf_resources
-
-    def _create_connection_point(self, account, c_point):
-        """
-        Create a connection point
-        Arguments:
-           account  - a cloud account
-           c_point  - connection_points
-        """
-        kwargs = {}
-        kwargs['name'] = c_point.name
-        kwargs['network_id'] = c_point.virtual_link_id
-        kwargs['admin_state_up'] = True
-
-        if c_point.type_yang == 'VIRTIO' or c_point.type_yang == 'E1000':
-            kwargs['port_type'] = 'normal'
-        elif c_point.type_yang == 'SR_IOV':
-            kwargs['port_type'] = 'direct'
-        else:
-            raise NotImplementedError("Port Type: %s not supported" %(c_point.type_yang))
-
-        # By default port gets created with post_security enaled as True
-        if 'port_security_enabled' in c_point:
-            kwargs['port_security_enabled'] = c_point.port_security_enabled
-
-        with self._use_driver(account) as drv:
-            if c_point.has_field('security_group'):
-                group = drv.neutron_security_group_by_name(c_point.security_group)
-                if group is not None:
-                    kwargs['security_groups'] = [group['id']]
-            return drv.neutron_port_create(**kwargs)
-
-    def _allocate_floating_ip(self, drv, pool_name):
-        """
-        Allocate a floating_ip. If unused floating_ip exists then its reused.
-        Arguments:
-          drv:       OpenstackDriver instance
-          pool_name: Floating IP pool name
-
-        Returns:
-          An object of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
-        """
-
-        # available_ip = [ ip for ip in drv.nova_floating_ip_list() if ip.instance_id == None ]
-
-        # if pool_name is not None:
-        #     ### Filter further based on IP address
-        #     available_ip = [ ip for ip in available_ip if ip.pool == pool_name ]
-
-        # if not available_ip:
-        #     floating_ip = drv.nova_floating_ip_create(pool_name)
-        # else:
-        #     floating_ip = available_ip[0]
-
-        floating_ip = drv.nova_floating_ip_create(pool_name)
-        return floating_ip
-
-    def _match_vm_flavor(self, required, available):
-        self.log.info("Matching VM Flavor attributes")
-        if available.vcpu_count != required.vcpu_count:
-            self.log.debug("VCPU requirement mismatch. Required: %d, Available: %d",
-                            required.vcpu_count,
-                            available.vcpu_count)
-            return False
-        if available.memory_mb != required.memory_mb:
-            self.log.debug("Memory requirement mismatch. Required: %d MB, Available: %d MB",
-                            required.memory_mb,
-                            available.memory_mb)
-            return False
-        if available.storage_gb != required.storage_gb:
-            self.log.debug("Storage requirement mismatch. Required: %d GB, Available: %d GB",
-                            required.storage_gb,
-                            available.storage_gb)
-            return False
-        self.log.debug("VM Flavor match found")
-        return True
-
-    def _match_guest_epa(self, required, available):
-        self.log.info("Matching Guest EPA attributes")
-        if required.has_field('pcie_device'):
-            self.log.debug("Matching pcie_device")
-            if available.has_field('pcie_device') == False:
-                self.log.debug("Matching pcie_device failed. Not available in flavor")
-                return False
-            else:
-                for dev in required.pcie_device:
-                    if not [ d for d in available.pcie_device
-                             if ((d.device_id == dev.device_id) and (d.count == dev.count)) ]:
-                        self.log.debug("Matching pcie_device failed. Required: %s, Available: %s", required.pcie_device, available.pcie_device)
-                        return False
-        elif available.has_field('pcie_device'):
-            self.log.debug("Rejecting available flavor because pcie_device not required but available")
-            return False
-
-
-        if required.has_field('mempage_size'):
-            self.log.debug("Matching mempage_size")
-            if available.has_field('mempage_size') == False:
-                self.log.debug("Matching mempage_size failed. Not available in flavor")
-                return False
-            else:
-                if required.mempage_size != available.mempage_size:
-                    self.log.debug("Matching mempage_size failed. Required: %s, Available: %s", required.mempage_size, available.mempage_size)
-                    return False
-        elif available.has_field('mempage_size'):
-            self.log.debug("Rejecting available flavor because mempage_size not required but available")
-            return False
-
-        if required.has_field('cpu_pinning_policy'):
-            self.log.debug("Matching cpu_pinning_policy")
-            if required.cpu_pinning_policy != 'ANY':
-                if available.has_field('cpu_pinning_policy') == False:
-                    self.log.debug("Matching cpu_pinning_policy failed. Not available in flavor")
-                    return False
-                else:
-                    if required.cpu_pinning_policy != available.cpu_pinning_policy:
-                        self.log.debug("Matching cpu_pinning_policy failed. Required: %s, Available: %s", required.cpu_pinning_policy, available.cpu_pinning_policy)
-                        return False
-        elif available.has_field('cpu_pinning_policy'):
-            self.log.debug("Rejecting available flavor because cpu_pinning_policy not required but available")
-            return False
-
-        if required.has_field('cpu_thread_pinning_policy'):
-            self.log.debug("Matching cpu_thread_pinning_policy")
-            if available.has_field('cpu_thread_pinning_policy') == False:
-                self.log.debug("Matching cpu_thread_pinning_policy failed. Not available in flavor")
-                return False
-            else:
-                if required.cpu_thread_pinning_policy != available.cpu_thread_pinning_policy:
-                    self.log.debug("Matching cpu_thread_pinning_policy failed. Required: %s, Available: %s", required.cpu_thread_pinning_policy, available.cpu_thread_pinning_policy)
-                    return False
-        elif available.has_field('cpu_thread_pinning_policy'):
-            self.log.debug("Rejecting available flavor because cpu_thread_pinning_policy not required but available")
-            return False
-
-        if required.has_field('trusted_execution'):
-            self.log.debug("Matching trusted_execution")
-            if required.trusted_execution == True:
-                if available.has_field('trusted_execution') == False:
-                    self.log.debug("Matching trusted_execution failed. Not available in flavor")
-                    return False
-                else:
-                    if required.trusted_execution != available.trusted_execution:
-                        self.log.debug("Matching trusted_execution failed. Required: %s, Available: %s", required.trusted_execution, available.trusted_execution)
-                        return False
-        elif available.has_field('trusted_execution'):
-            self.log.debug("Rejecting available flavor because trusted_execution not required but available")
-            return False
-
-        if required.has_field('numa_node_policy'):
-            self.log.debug("Matching numa_node_policy")
-            if available.has_field('numa_node_policy') == False:
-                self.log.debug("Matching numa_node_policy failed. Not available in flavor")
-                return False
-            else:
-                if required.numa_node_policy.has_field('node_cnt'):
-                    self.log.debug("Matching numa_node_policy node_cnt")
-                    if available.numa_node_policy.has_field('node_cnt') == False:
-                        self.log.debug("Matching numa_node_policy node_cnt failed. Not available in flavor")
-                        return False
-                    else:
-                        if required.numa_node_policy.node_cnt != available.numa_node_policy.node_cnt:
-                            self.log.debug("Matching numa_node_policy node_cnt failed. Required: %s, Available: %s",required.numa_node_policy.node_cnt, available.numa_node_policy.node_cnt)
-                            return False
-                elif available.numa_node_policy.has_field('node_cnt'):
-                    self.log.debug("Rejecting available flavor because numa node count not required but available")
-                    return False
-
-                if required.numa_node_policy.has_field('mem_policy'):
-                    self.log.debug("Matching numa_node_policy mem_policy")
-                    if available.numa_node_policy.has_field('mem_policy') == False:
-                        self.log.debug("Matching numa_node_policy mem_policy failed. Not available in flavor")
-                        return False
-                    else:
-                        if required.numa_node_policy.mem_policy != available.numa_node_policy.mem_policy:
-                            self.log.debug("Matching numa_node_policy mem_policy failed. Required: %s, Available: %s", required.numa_node_policy.mem_policy, available.numa_node_policy.mem_policy)
-                            return False
-                elif available.numa_node_policy.has_field('mem_policy'):
-                    self.log.debug("Rejecting available flavor because num node mem_policy not required but available")
-                    return False
-
-                if required.numa_node_policy.has_field('node'):
-                    self.log.debug("Matching numa_node_policy nodes configuration")
-                    if available.numa_node_policy.has_field('node') == False:
-                        self.log.debug("Matching numa_node_policy nodes configuration failed. Not available in flavor")
-                        return False
-                    for required_node in required.numa_node_policy.node:
-                        self.log.debug("Matching numa_node_policy nodes configuration for node %s", required_node)
-                        numa_match = False
-                        for available_node in available.numa_node_policy.node:
-                            if required_node.id != available_node.id:
-                                self.log.debug("Matching numa_node_policy nodes configuration failed. Required: %s, Available: %s", required_node, available_node)
-                                continue
-                            if required_node.vcpu != available_node.vcpu:
-                                self.log.debug("Matching numa_node_policy nodes configuration failed. Required: %s, Available: %s", required_node, available_node)
-                                continue
-                            if required_node.memory_mb != available_node.memory_mb:
-                                self.log.debug("Matching numa_node_policy nodes configuration failed. Required: %s, Available: %s", required_node, available_node)
-                                continue
-                            numa_match = True
-                        if numa_match == False:
-                            return False
-                elif available.numa_node_policy.has_field('node'):
-                    self.log.debug("Rejecting available flavor because numa nodes not required but available")
-                    return False
-        elif available.has_field('numa_node_policy'):
-            self.log.debug("Rejecting available flavor because numa_node_policy not required but available")
-            return False
-        self.log.info("Successful match for Guest EPA attributes")
-        return True
-
-    def _match_vswitch_epa(self, required, available):
-        self.log.debug("VSwitch EPA match found")
-        return True
-
-    def _match_hypervisor_epa(self, required, available):
-        self.log.debug("Hypervisor EPA match found")
-        return True
-
-    def _match_host_epa(self, required, available):
-        self.log.info("Matching Host EPA attributes")
-        if required.has_field('cpu_model'):
-            self.log.debug("Matching CPU model")
-            if available.has_field('cpu_model') == False:
-                self.log.debug("Matching CPU model failed. Not available in flavor")
-                return False
-            else:
-                #### Convert all PREFER to REQUIRE since flavor will only have REQUIRE attributes
-                if required.cpu_model.replace('PREFER', 'REQUIRE') != available.cpu_model:
-                    self.log.debug("Matching CPU model failed. Required: %s, Available: %s", required.cpu_model, available.cpu_model)
-                    return False
-        elif available.has_field('cpu_model'):
-            self.log.debug("Rejecting available flavor because cpu_model not required but available")
-            return False
-
-        if required.has_field('cpu_arch'):
-            self.log.debug("Matching CPU architecture")
-            if available.has_field('cpu_arch') == False:
-                self.log.debug("Matching CPU architecture failed. Not available in flavor")
-                return False
-            else:
-                #### Convert all PREFER to REQUIRE since flavor will only have REQUIRE attributes
-                if required.cpu_arch.replace('PREFER', 'REQUIRE') != available.cpu_arch:
-                    self.log.debug("Matching CPU architecture failed. Required: %s, Available: %s", required.cpu_arch, available.cpu_arch)
-                    return False
-        elif available.has_field('cpu_arch'):
-            self.log.debug("Rejecting available flavor because cpu_arch not required but available")
-            return False
-
-        if required.has_field('cpu_vendor'):
-            self.log.debug("Matching CPU vendor")
-            if available.has_field('cpu_vendor') == False:
-                self.log.debug("Matching CPU vendor failed. Not available in flavor")
-                return False
-            else:
-                #### Convert all PREFER to REQUIRE since flavor will only have REQUIRE attributes
-                if required.cpu_vendor.replace('PREFER', 'REQUIRE') != available.cpu_vendor:
-                    self.log.debug("Matching CPU vendor failed. Required: %s, Available: %s", required.cpu_vendor, available.cpu_vendor)
-                    return False
-        elif available.has_field('cpu_vendor'):
-            self.log.debug("Rejecting available flavor because cpu_vendor not required but available")
-            return False
-
-        if required.has_field('cpu_socket_count'):
-            self.log.debug("Matching CPU socket count")
-            if available.has_field('cpu_socket_count') == False:
-                self.log.debug("Matching CPU socket count failed. Not available in flavor")
-                return False
-            else:
-                if required.cpu_socket_count != available.cpu_socket_count:
-                    self.log.debug("Matching CPU socket count failed. Required: %s, Available: %s", required.cpu_socket_count, available.cpu_socket_count)
-                    return False
-        elif available.has_field('cpu_socket_count'):
-            self.log.debug("Rejecting available flavor because cpu_socket_count not required but available")
-            return False
-
-        if required.has_field('cpu_core_count'):
-            self.log.debug("Matching CPU core count")
-            if available.has_field('cpu_core_count') == False:
-                self.log.debug("Matching CPU core count failed. Not available in flavor")
-                return False
-            else:
-                if required.cpu_core_count != available.cpu_core_count:
-                    self.log.debug("Matching CPU core count failed. Required: %s, Available: %s", required.cpu_core_count, available.cpu_core_count)
-                    return False
-        elif available.has_field('cpu_core_count'):
-            self.log.debug("Rejecting available flavor because cpu_core_count not required but available")
-            return False
-
-        if required.has_field('cpu_core_thread_count'):
-            self.log.debug("Matching CPU core thread count")
-            if available.has_field('cpu_core_thread_count') == False:
-                self.log.debug("Matching CPU core thread count failed. Not available in flavor")
-                return False
-            else:
-                if required.cpu_core_thread_count != available.cpu_core_thread_count:
-                    self.log.debug("Matching CPU core thread count failed. Required: %s, Available: %s", required.cpu_core_thread_count, available.cpu_core_thread_count)
-                    return False
-        elif available.has_field('cpu_core_thread_count'):
-            self.log.debug("Rejecting available flavor because cpu_core_thread_count not required but available")
-            return False
-
-        if required.has_field('cpu_feature'):
-            self.log.debug("Matching CPU feature list")
-            if available.has_field('cpu_feature') == False:
-                self.log.debug("Matching CPU feature list failed. Not available in flavor")
-                return False
-            else:
-                for feature in required.cpu_feature:
-                    if feature not in available.cpu_feature:
-                        self.log.debug("Matching CPU feature list failed. Required feature: %s is not present. Available features: %s", feature, available.cpu_feature)
-                        return False
-        elif available.has_field('cpu_feature'):
-            self.log.debug("Rejecting available flavor because cpu_feature not required but available")
-            return False
-        self.log.info("Successful match for Host EPA attributes")
-        return True
-
-
-    def _match_placement_group_inputs(self, required, available):
-        self.log.info("Matching Host aggregate attributes")
-
-        if not required and not available:
-            # Host aggregate not required and not available => success
-            self.log.info("Successful match for Host Aggregate attributes")
-            return True
-        if required and available:
-            # Host aggregate requested and available => Do a match and decide
-            xx = [ x.as_dict() for x in required ]
-            yy = [ y.as_dict() for y in available ]
-            for i in xx:
-                if i not in yy:
-                    self.log.debug("Rejecting available flavor because host Aggregate mismatch. Required: %s, Available: %s ", required, available)
-                    return False
-            self.log.info("Successful match for Host Aggregate attributes")
-            return True
-        else:
-            # Either of following conditions => Failure
-            #  - Host aggregate required but not available
-            #  - Host aggregate not required but available
-            self.log.debug("Rejecting available flavor because host Aggregate mismatch. Required: %s, Available: %s ", required, available)
-            return False
-
-    def match_epa_params(self, resource_info, request_params):
-        result = self._match_vm_flavor(getattr(request_params, 'vm_flavor'),
-                                       getattr(resource_info, 'vm_flavor'))
-        if result == False:
-            self.log.debug("VM Flavor mismatched")
-            return False
-
-        result = self._match_guest_epa(getattr(request_params, 'guest_epa'),
-                                       getattr(resource_info, 'guest_epa'))
-        if result == False:
-            self.log.debug("Guest EPA mismatched")
-            return False
-
-        result = self._match_vswitch_epa(getattr(request_params, 'vswitch_epa'),
-                                         getattr(resource_info, 'vswitch_epa'))
-        if result == False:
-            self.log.debug("Vswitch EPA mismatched")
-            return False
-
-        result = self._match_hypervisor_epa(getattr(request_params, 'hypervisor_epa'),
-                                            getattr(resource_info, 'hypervisor_epa'))
-        if result == False:
-            self.log.debug("Hypervisor EPA mismatched")
-            return False
-
-        result = self._match_host_epa(getattr(request_params, 'host_epa'),
-                                      getattr(resource_info, 'host_epa'))
-        if result == False:
-            self.log.debug("Host EPA mismatched")
-            return False
-
-        result = self._match_placement_group_inputs(getattr(request_params, 'host_aggregate'),
-                                                    getattr(resource_info, 'host_aggregate'))
-
-        if result == False:
-            self.log.debug("Host Aggregate mismatched")
-            return False
-
-        return True
-
-    def _select_resource_flavor(self, account, vdu_init):
-        """
-            Select a existing flavor if it matches the request or create new flavor
-        """
-        flavor = RwcalYang.FlavorInfoItem()
-        flavor.name = str(uuid.uuid4())
-        epa_types = ['vm_flavor', 'guest_epa', 'host_epa', 'host_aggregate', 'hypervisor_epa', 'vswitch_epa']
-        epa_dict = {k: v for k, v in vdu_init.as_dict().items() if k in epa_types}
-        flavor.from_dict(epa_dict)
-
-        rc, response = self.do_get_flavor_list(account)
-        if rc != RwTypes.RwStatus.SUCCESS:
-            self.log.error("Get-flavor-info-list operation failed for cloud account: %s",
-                        account.name)
-            raise OpenstackCALOperationFailure("Get-flavor-info-list operation failed for cloud account: %s" %(account.name))
-
-        flavor_id = None
-        flavor_list = response.flavorinfo_list
-        self.log.debug("Received %d flavor information from RW.CAL", len(flavor_list))
-        for flv in flavor_list:
-            self.log.info("Attempting to match compute requirement for VDU: %s with flavor %s",
-                       vdu_init.name, flv)
-            if self.match_epa_params(flv, vdu_init):
-                self.log.info("Flavor match found for compute requirements for VDU: %s with flavor name: %s, flavor-id: %s",
-                           vdu_init.name, flv.name, flv.id)
-                return flv.id
-
-        if account.openstack.dynamic_flavor_support is False:
-            self.log.error("Unable to create flavor for compute requirement for VDU: %s. VDU instantiation failed", vdu_init.name)
-            raise OpenstackCALOperationFailure("No resource available with matching EPA attributes")
-        else:
-            rc,flavor_id = self.do_create_flavor(account,flavor)
-            if rc != RwTypes.RwStatus.SUCCESS:
-                self.log.error("Create-flavor operation failed for cloud account: %s",
-                        account.name)
-                raise OpenstackCALOperationFailure("Create-flavor operation failed for cloud account: %s" %(account.name))
-            return flavor_id
-
-    def _create_vm(self, account, vduinfo, pci_assignement=None, server_group=None, port_list=None, network_list=None, imageinfo_list=None):
-        """Create a new virtual machine.
-
-        Arguments:
-            account - a cloud account
-            vminfo - information that defines the type of VM to create
-
-        Returns:
-            The image id
-        """
-        kwargs = {}
-        kwargs['name']      = vduinfo.name
-        kwargs['flavor_id'] = vduinfo.flavor_id
-        if vduinfo.has_field('image_id'):
-            kwargs['image_id']  = vduinfo.image_id
-        else:
-            kwargs['image_id']  = ""
-
-        with self._use_driver(account) as drv:
-            ### If floating_ip is required and we don't have one, better fail before any further allocation
-            floating_ip = False
-            pool_name = None
-            if vduinfo.has_field('allocate_public_address') and vduinfo.allocate_public_address:
-                if account.openstack.has_field('floating_ip_pool'):
-                    pool_name = account.openstack.floating_ip_pool
-                floating_ip = True
-
-        if vduinfo.has_field('vdu_init') and vduinfo.vdu_init.has_field('userdata'):
-            kwargs['userdata'] = vduinfo.vdu_init.userdata
-        else:
-            kwargs['userdata'] = ''
-
-        if account.openstack.security_groups:
-            kwargs['security_groups'] = account.openstack.security_groups
-
-        kwargs['port_list'] = port_list
-        kwargs['network_list'] = network_list
-
-        metadata = {}
-        files = {}
-        config_drive = False
-        # Add all metadata related fields
-        if vduinfo.has_field('node_id'):
-            metadata['node_id'] = vduinfo.node_id
-        if pci_assignement is not None:
-            metadata['pci_assignement'] = pci_assignement
-        if vduinfo.has_field('supplemental_boot_data'):
-            if vduinfo.supplemental_boot_data.has_field('custom_meta_data'):
-                for custom_meta_item in vduinfo.supplemental_boot_data.custom_meta_data:
-                    if custom_meta_item.data_type == "STRING":
-                       metadata[custom_meta_item.name] = custom_meta_item.value
-                    elif custom_meta_item.data_type == "JSON":
-                       metadata[custom_meta_item.name] = tornado.escape.json_decode(custom_meta_item.value)
-                    else:
-                       raise OpenstackCALOperationFailure("Create-vdu operation failed. Unsupported data-type {} for custom-meta-data name {} ".format(custom_meta_item.data_type, custom_meta_item.name))
-            if vduinfo.supplemental_boot_data.has_field('config_file'):
-                for custom_config_file in vduinfo.supplemental_boot_data.config_file:
-                    files[custom_config_file.dest] = custom_config_file.source
-
-            if vduinfo.supplemental_boot_data.has_field('boot_data_drive'):
-                if vduinfo.supplemental_boot_data.boot_data_drive is True:
-                     config_drive = True
-                     
-        kwargs['metadata'] = metadata
-        kwargs['files'] = files
-        kwargs['config_drive'] = config_drive
-
-        if vduinfo.has_field('availability_zone') and vduinfo.availability_zone.has_field('name'):
-            kwargs['availability_zone']  = vduinfo.availability_zone
-        else:
-            kwargs['availability_zone'] = None
-
-        if server_group is not None:
-            kwargs['scheduler_hints'] = {'group': server_group}
-        else:
-            kwargs['scheduler_hints'] = None
-
-        kwargs['block_device_mapping_v2'] = None
-        vol_metadata = False
-        if vduinfo.has_field('volumes') :
-            kwargs['block_device_mapping_v2'] = []
-            with self._use_driver(account) as drv:
-            # Only support image->volume
-                for volume in vduinfo.volumes:
-                    block_map = dict()
-                    block_map['boot_index'] = volume.boot_priority
-                    if "image" in volume:
-                        # Support image->volume
-                        # Match retrived image info with volume based image name and checksum
-                        if volume.image is not None:
-                           matching_images = [img for img in imageinfo_list if img['name'] == volume.image]
-                           if volume.image_checksum is not None:
-                              matching_images = [img for img in matching_images if img['checksum'] == volume.image_checksum]
-                           img_id = matching_images[0]['id']
-                        if img_id is None:
-                           raise OpenstackCALOperationFailure("Create-vdu operation failed. Volume image not found for name {} checksum {}".format(volume.name, volume.checksum))
-                        block_map['uuid'] = img_id
-                        block_map['source_type'] = "image"
-                    else:
-                        block_map['source_type'] = "blank"
-                        
-                    block_map['device_name'] = volume.name
-                    block_map['destination_type'] = "volume"
-                    block_map['volume_size'] = volume.size
-                    block_map['delete_on_termination'] = True
-                    if volume.has_field('device_type') and volume.device_type == 'cdrom':
-                        block_map['device_type'] = 'cdrom'
-                    if volume.has_field('device_bus') and volume.device_bus == 'ide':
-                        block_map['disk_bus'] = 'ide'
-                    kwargs['block_device_mapping_v2'].append(block_map)
-                
-           
-        with self._use_driver(account) as drv:
-            vm_id = drv.nova_server_create(**kwargs)
-            if floating_ip:
-                self.prepare_vdu_on_boot(account, vm_id, floating_ip, pool_name, vduinfo.volumes)
+        except Exception as e:
+            self.log.exception("Exception %s occured during virtual-link-list-get", str(e))
+            raise
+        return vnf_resources
 
-        return vm_id
 
-    def get_openstack_image_info(self, account, image_name, image_checksum=None):
-        self.log.debug("Looking up image id for image name %s and checksum %s on cloud account: %s",
-                image_name, image_checksum, account.name
-                )
-
-        image_list = []
-        with self._use_driver(account) as drv:
-            image_list = drv.glance_image_list()
-        matching_images = [img for img in image_list if img['name'] == image_name]
-  
-        # If the image checksum was filled in then further filter the images by the checksum
-        if image_checksum is not None:
-            matching_images = [img for img in matching_images if img['checksum'] == image_checksum]
-        else:
-            self.log.warning("Image checksum not provided.  Lookup using image name (%s) only.",
-                                image_name) 
-  
-        if len(matching_images) == 0:
-            raise ResMgrCALOperationFailure("Could not find image name {} (using checksum: {}) for cloud account: {}".format(
-                  image_name, image_checksum, account.name
-                  ))
-  
-        elif len(matching_images) > 1:
-            unique_checksums = {i.checksum for i in matching_images}
-            if len(unique_checksums) > 1:
-                msg = ("Too many images with different checksums matched "
-                         "image name of %s for cloud account: %s" % (image_name, account.name))
-                raise ResMgrCALOperationFailure(msg)
-  
-        return matching_images[0]
 
     @rwcalstatus(ret_on_failure=[""])
     def do_create_vdu(self, account, vdu_init):
@@ -2060,162 +1001,18 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             The vdu_id
         """
-        ### First create required number of ports aka connection points
-        # Add the mgmt_ntwk by default.
-        mgmt_network_id = None
-        with self._use_driver(account) as drv:
-            mgmt_network_id = drv._mgmt_network_id
-
-        port_list = []
-        network_list = []
-        imageinfo_list = []
-        is_explicit_mgmt_defined = False
-        for c_point in vdu_init.connection_points:
-            # if the user has specified explicit mgmt_network connection point
-            # then remove the mgmt_network from the VM list
-            if c_point.virtual_link_id == mgmt_network_id:
-                is_explicit_mgmt_defined = True
-            if c_point.virtual_link_id in network_list:
-                assert False, "Only one port per network supported. Refer: http://specs.openstack.org/openstack/nova-specs/specs/juno/implemented/nfv-multiple-if-1-net.html"
-            else:
-                network_list.append(c_point.virtual_link_id)
-            port_id = self._create_connection_point(account, c_point)
-            port_list.append(port_id)
-
-        if not vdu_init.has_field('flavor_id'):
-            vdu_init.flavor_id = self._select_resource_flavor(account,vdu_init)
-
-        ### Obtain all images for volumes and perform validations
-        if vdu_init.has_field('volumes'):
-            for volume in vdu_init.volumes:
-                if "image" in volume:
-                    image_checksum = volume.image_checksum if volume.has_field("image_checksum") else None
-                    image_info = self.get_openstack_image_info(account, volume.image, image_checksum)
-                    imageinfo_list.append(image_info)
-        elif vdu_init.has_field('image_id'):
-            with self._use_driver(account) as drv:
-                image_info = drv.glance_image_get(vdu_init.image_id)
-                imageinfo_list.append(image_info)
-
-        if not imageinfo_list:
-            err_str = ("VDU has no image information")
-            self.log.error(err_str)
-            raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
-
-        ### Check VDU Virtual Interface type and make sure VM with property exists
-        if vdu_init.connection_points:
-                ### All virtual interfaces need to be of the same type for Openstack Accounts
-                if not (all(cp.type_yang == 'E1000' for cp in vdu_init.connection_points) or all(cp.type_yang != 'E1000' for cp in vdu_init.connection_points)):
-                    ### We have a mix of E1000 & VIRTIO/SR_IPOV virtual interface types in the VDU, abort instantiation.
-                    assert False, "Only one type of Virtual Intefaces supported for Openstack accounts. Found a mix of VIRTIO/SR_IOV &   E1000."
-  
-                ## It is not clear if all the images need to checked for HW properties. In the absence of model info describing each im  age's properties,
-                ###   we shall assume that all images need to have similar properties
-                for img_info in imageinfo_list:
-  
-                    virt_intf_type = vdu_init.connection_points[0].type_yang
-                    if virt_intf_type == 'E1000':
-                        if 'hw_vif_model' in img_info and img_info.hw_vif_model == 'e1000':
-                            self.log.debug("VDU has Virtual Interface E1000, found matching image with property hw_vif_model=e1000")
-                        else:
-                            err_str = ("VDU has Virtual Interface E1000, but image '%s' does not have property hw_vif_model=e1000" % img_info.name)
-                            self.log.error(err_str)
-                            raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
-                    elif virt_intf_type == 'VIRTIO' or virt_intf_type == 'SR_IOV':
-                        if 'hw_vif_model' in img_info:
-                            err_str = ("VDU has Virtual Interface %s, but image '%s' has hw_vif_model mismatch" % virt_intf_type,img_info.name)
-                            self.log.error(err_str)
-                            raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
-                        else:
-                            self.log.debug("VDU has Virtual Interface %s, found matching image" % virt_intf_type)
-                    else:
-                        err_str = ("VDU Virtual Interface '%s' not supported yet" % virt_intf_type)
-                        self.log.error(err_str)
-                        raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str) 
+        drv =  self._use_driver(account)
+        try:
+            kwargs = drv.utils.compute.make_vdu_create_args(vdu_init, account)
+            vm_id = drv.nova_server_create(**kwargs)
+            self.prepare_vdu_on_boot(account, vm_id, vdu_init)
+        except Exception as e:
+            self.log.exception("Exception %s occured during create-vdu", str(e))
+            raise
+        return vm_id
+    
 
-        with self._use_driver(account) as drv:
-            ### Now Create VM
-            vm_network_list = []
-            if not is_explicit_mgmt_defined:
-                vm_network_list.append(drv._mgmt_network_id)
-  
-            if vdu_init.has_field('volumes'):
-                  # Only combination supported: Image->Volume
-                  for volume in vdu_init.volumes:
-                      if "volume" in volume:
-                          err_str = ("VDU Volume source not supported yet")
-                          self.log.error(err_str)
-                          raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
-                      if not volume.has_field('device_type'):
-                          err_str = ("VDU Volume destination type not defined")
-                          self.log.error(err_str)
-                          raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
-                      if volume.device_type not in ['disk', 'cdrom'] :
-                          err_str = ("VDU Volume destination type '%s' not supported" % volume.device_type)
-                          self.log.error(err_str)
-                          raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
-  
-  
-            server_group = None
-            if vdu_init.has_field('server_group'):
-                  ### Get list of server group in openstack for name->id mapping
-                  openstack_group_list = drv.nova_server_group_list()
-                  group_id = [ i['id'] for i in openstack_group_list if i['name'] == vdu_init.server_group.name]
-                  if len(group_id) != 1:
-                      raise OpenstackServerGroupError("VM placement failed. Server Group %s not found in openstack. Available groups" %(vdu_init.server_group.name, [i['name'] for i in openstack_group_list]))
-                  server_group = group_id[0]
-
-            pci_assignement = self.prepare_vpci_metadata(drv, vdu_init)
-            if pci_assignement != '':
-                vm.user_tags.pci_assignement = pci_assignement
-
-            vm_id = self._create_vm(account, vdu_init, pci_assignement=pci_assignement, server_group=server_group, port_list=port_list, network_list=vm_network_list, imageinfo_list = imageinfo_list)
-            return vm_id
-
-    def prepare_vpci_metadata(self, drv, vdu_init):
-        pci_assignement = ''
-        ### TEF specific metadata creation for
-        virtio_vpci = []
-        sriov_vpci = []
-        virtio_meta = ''
-        sriov_meta = ''
-        ### For MGMT interface
-        if vdu_init.has_field('mgmt_vpci'):
-            xx = 'u\''+ drv._mgmt_network_id + '\' :[[u\'' + vdu_init.mgmt_vpci + '\', ' + '\'\']]'
-            virtio_vpci.append(xx)
-
-        for c_point in vdu_init.connection_points:
-            if c_point.has_field('vpci'):
-                if c_point.has_field('vpci') and c_point.type_yang == 'VIRTIO':
-                    xx = 'u\''+c_point.virtual_link_id + '\' :[[u\'' + c_point.vpci + '\', ' + '\'\']]'
-                    virtio_vpci.append(xx)
-                elif c_point.has_field('vpci') and c_point.type_yang == 'SR_IOV':
-                    xx = '[u\'' + c_point.vpci + '\', ' + '\'\']'
-                    sriov_vpci.append(xx)
-
-        if virtio_vpci:
-            virtio_meta += ','.join(virtio_vpci)
-
-        if sriov_vpci:
-            sriov_meta = 'u\'VF\': ['
-            sriov_meta += ','.join(sriov_vpci)
-            sriov_meta += ']'
-
-        if virtio_meta != '':
-            pci_assignement +=  virtio_meta
-            pci_assignement += ','
-
-        if sriov_meta != '':
-            pci_assignement +=  sriov_meta
-
-        if pci_assignement != '':
-            pci_assignement = '{' + pci_assignement + '}'
-
-        return pci_assignement
-
-
-
-    def prepare_vdu_on_boot(self, account, server_id, floating_ip,  pool_name, volumes=None):
+    def prepare_vdu_on_boot(self, account, server_id, vdu_params):
         cmd = PREPARE_VM_CMD.format(auth_url       = account.openstack.auth_url,
                                     username       = account.openstack.key,
                                     password       = account.openstack.secret,
@@ -2225,29 +1022,23 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
                                     project_domain = account.openstack.project_domain,
                                     mgmt_network   = account.openstack.mgmt_network,
                                     server_id      = server_id)
-        if floating_ip:
+        vol_list = list()
+        
+        if vdu_params.has_field('allocate_public_address') and vdu_params.allocate_public_address:
             cmd += " --floating_ip"
-        if pool_name:
-            cmd += (" --pool_name " + pool_name)
-
-        vol_metadata = False
-        if volumes is not None:
-            for volume in volumes:
-                if volume.has_field('custom_meta_data'):
-                    vol_metadata = True
-                    break
+            if account.openstack.has_field('floating_ip_pool'):
+                cmd += (" --pool_name " + account.openstack.floating_ip_pool)
         
-        if vol_metadata is True:       
-            tmp_file = None
-            with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_file:
-                 vol_list = list()
-                 for volume in volumes:
-                    vol_dict = volume.as_dict()
-                    vol_list.append(vol_dict)
-
-                 yaml.dump(vol_list, tmp_file)
-            cmd += (" --vol_metadata {}").format(tmp_file.name)
+        if vdu_params.has_field('volumes'):
+            for volume in vdu_params.volumes:
+                if volume.has_field('custom_meta_data'):
+                    vol_list.append(volume.as_dict())
 
+        if vol_list:
+            with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_file:
+                yaml.dump(vol_list, tmp_file)
+                cmd += (" --vol_metadata {}").format(tmp_file.name)
+            
         exec_path = 'python3 ' + os.path.dirname(openstack_drv.__file__)
         exec_cmd = exec_path+'/'+cmd
         self.log.info("Running command: %s" %(exec_cmd))
@@ -2261,6 +1052,7 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             account     -  a cloud account
             vdu_modify  -  Information about VDU Modification (RwcalYang.VDUModifyParams)
         """
+        drv = self._use_driver(account)
         ### First create required number of ports aka connection points
         port_list = []
         network_list = []
@@ -2272,18 +1064,17 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             port_id = self._create_connection_point(account, c_point)
             port_list.append(port_id)
 
+        drv = self._use_driver(account)
         ### Now add the ports to VM
         for port_id in port_list:
-            with self._use_driver(account) as drv:
-                drv.nova_server_add_port(vdu_modify.vdu_id, port_id)
+            drv.nova_server_add_port(vdu_modify.vdu_id, port_id)
 
         ### Delete the requested connection_points
         for c_point in vdu_modify.connection_points_remove:
             self.do_delete_port(account, c_point.connection_point_id, no_rwstatus=True)
 
         if vdu_modify.has_field('image_id'):
-            with self._use_driver(account) as drv:
-                drv.nova_server_rebuild(vdu_modify.vdu_id, vdu_modify.image_id)
+            drv.nova_server_rebuild(vdu_modify.vdu_id, vdu_modify.image_id)
 
 
     @rwstatus
@@ -2297,25 +1088,14 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             None
         """
-        if not vdu_id:
-            self.log.error("empty vdu_id during the vdu deletion")
-            return
-
-        with self._use_driver(account) as drv:
-            ### Get list of floating_ips associated with this instance and delete them
-            floating_ips = [ f for f in drv.nova_floating_ip_list() if f.instance_id == vdu_id ]
-            for f in floating_ips:
-                drv.nova_drv.floating_ip_delete(f)
-
-            ### Get list of port on VM and delete them.
-            port_list = drv.neutron_port_list(**{'device_id': vdu_id})
-
-        for port in port_list:
-            if ((port['device_owner'] == 'compute:None') or (port['device_owner'] == '')):
-                self.do_delete_port(account, port['id'], no_rwstatus=True)
-
-        self.do_delete_vm(account, vdu_id, no_rwstatus=True)
-
+        drv = self._use_driver(account)
+        try:
+            drv.utils.compute.perform_vdu_network_cleanup(vdu_id)
+            drv.nova_server_delete(vdu_id)
+        except Exception as e:
+            self.log.exception("Exception %s occured during delete-vdu", str(e))
+            raise
+            
 
     @rwstatus(ret_on_failure=[None])
     def do_get_vdu(self, account, vdu_id):
@@ -2328,37 +1108,15 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             Object of type RwcalYang.VDUInfoParams
         """
-        with self._use_driver(account) as drv:
-            port_list = drv.neutron_port_list(**{'device_id': vdu_id})
-
-            vm = drv.nova_server_get(vdu_id)
-
-            flavor_info = None
-            if ('flavor' in vm) and ('id' in vm['flavor']):
-                try:
-                    flavor_info = drv.nova_flavor_get(vm['flavor']['id'])
-                except Exception as e:
-                    self.log.critical("Exception encountered while attempting to get flavor info for flavor_id: %s. Exception: %s" %(vm['flavor']['id'], str(e)))
-
-            openstack_group_list = drv.nova_server_group_list()
-            server_group = [ i['name'] for i in openstack_group_list if vm['id'] in i['members']]
-            openstack_srv_volume_list = drv.nova_volume_list(vm['id'])
-            vdu_info = RwcalOpenstackPlugin._fill_vdu_info(drv, vm,
-                                                           flavor_info,
-                                                           account.openstack.mgmt_network,
-                                                           port_list,
-                                                           server_group,
-                                                           volume_list = openstack_srv_volume_list)
-            if vdu_info.state == 'active':
-                try:
-                    console_info = drv.nova_server_console(vdu_info.vdu_id)
-                except Exception as e:
-                    pass
-                else:
-                    vdu_info.console_url = console_info['console']['url']
-                    pass
-
-            return vdu_info
+        drv = self._use_driver(account)
+        try:
+            vm_info = drv.nova_server_get(vdu_id)
+            vdu_info = drv.utils.compute.parse_cloud_vdu_info(vm_info)
+        except Exception as e:
+            self.log.exception("Exception %s occured during get-vdu", str(e))
+            raise
+        
+        return vdu_info
 
 
     @rwstatus(ret_on_failure=[None])
@@ -2372,41 +1130,188 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             A list of objects of type RwcalYang.VDUInfoParams
         """
         vnf_resources = RwcalYang.VNFResources()
-        with self._use_driver(account) as drv:
+        drv = self._use_driver(account)
+        try:
             vms = drv.nova_server_list()
             for vm in vms:
-                port_list = drv.neutron_port_list(**{'device_id': vm['id']})
+                vdu = drv.utils.compute.parse_cloud_vdu_info(vm)
+                vnf_resources.vdu_info_list.append(vdu)
+        except Exception as e:
+            self.log.exception("Exception %s occured during get-vdu-list", str(e))
+            raise
+        return vnf_resources
+
+
+class SdnOpenstackPlugin(GObject.Object, RwSdn.Topology):
+    instance_num = 1
+    def __init__(self):
+        GObject.Object.__init__(self)
+        self._driver_class = openstack_drv.OpenstackDriver
+        self.log = logging.getLogger('rwsdn.openstack.%s' % SdnOpenstackPlugin.instance_num)
+        self.log.setLevel(logging.DEBUG)
+
+        self._rwlog_handler = None
+        SdnOpenstackPlugin.instance_num += 1
+
+    @contextlib.contextmanager
+    def _use_driver(self, account):
+        if self._rwlog_handler is None:
+            raise UninitializedPluginError("Must call init() in CAL plugin before use.")
+
+        with rwlogger.rwlog_root_handler(self._rwlog_handler):
+            try:
+                drv = self._driver_class(username      = account.openstack.key,
+                                         password      = account.openstack.secret,
+                                         auth_url      = account.openstack.auth_url,
+                                         tenant_name   = account.openstack.tenant,
+                                         mgmt_network  = account.openstack.mgmt_network,
+                                         cert_validate = account.openstack.cert_validate )
+            except Exception as e:
+                self.log.error("SdnOpenstackPlugin: OpenstackDriver init failed. Exception: %s" %(str(e)))
+                raise
 
-                flavor_info = None
+            yield drv
+
+    @rwstatus
+    def do_init(self, rwlog_ctx):
+        self._rwlog_handler = rwlogger.RwLogger(
+                category="rw-cal-log",
+                subcategory="openstack",
+                log_hdl=rwlog_ctx,
+                )
+        self.log.addHandler(self._rwlog_handler)
+        self.log.propagate = False
+
+    @rwstatus(ret_on_failure=[None])
+    def do_validate_sdn_creds(self, account):
+        """
+        Validates the sdn account credentials for the specified account.
+        Performs an access to the resources using Keystone API. If creds
+        are not valid, returns an error code & reason string
 
-                if ('flavor' in vm) and ('id' in vm['flavor']):
-                    try:
-                        flavor_info = drv.nova_flavor_get(vm['flavor']['id'])
-                    except Exception as e:
-                        self.log.critical("Exception encountered while attempting to get flavor info for flavor_id: %s. Exception: %s" %(vm['flavor']['id'], str(e)))
+        @param account - a SDN account
 
+        Returns:
+            Validation Code and Details String
+        """
+        status = RwsdnYang.SdnConnectionStatus()
+        try:
+            with self._use_driver(account) as drv:
+                drv.validate_account_creds()
+
+        except openstack_drv.ValidationError as e:
+            self.log.error("SdnOpenstackPlugin: OpenstackDriver credential validation failed. Exception: %s", str(e))
+            status.status = "failure"
+            status.details = "Invalid Credentials: %s" % str(e)
+
+        except Exception as e:
+            msg = "SdnOpenstackPlugin: OpenstackDriver connection failed. Exception: %s" %(str(e))
+            self.log.error(msg)
+            status.status = "failure"
+            status.details = msg
+
+        else:
+            status.status = "success"
+            status.details = "Connection was successful"
+
+        return status
+
+    @rwstatus(ret_on_failure=[""])
+    def do_create_vnffg_chain(self, account,vnffg):
+        """
+        Creates Service Function chain in ODL
+
+        @param account - a SDN account
+
+        """
+        self.log.debug('Received Create VNFFG chain for account {}, chain {}'.format(account,vnffg))
+        with self._use_driver(account) as drv:
+            port_list = list()
+            vnf_chain_list = sorted(vnffg.vnf_chain_path, key = lambda x: x.order)
+            prev_vm_id = None 
+            for path in vnf_chain_list:
+                if prev_vm_id and path.vnfr_ids[0].vdu_list[0].vm_id == prev_vm_id:
+                    prev_entry = port_list.pop()
+                    port_list.append((prev_entry[0],path.vnfr_ids[0].vdu_list[0].port_id))
+                    prev_vm_id = None
                 else:
-                    flavor_info = None
-
-                openstack_group_list = drv.nova_server_group_list()
-                server_group = [ i['name'] for i in openstack_group_list if vm['id'] in i['members']]
-
-                openstack_srv_volume_list = drv.nova_volume_list(vm['id'])
-                vdu = RwcalOpenstackPlugin._fill_vdu_info(drv, vm,
-                                                          flavor_info,
-                                                          account.openstack.mgmt_network,
-                                                          port_list,
-                                                          server_group,
-                                                          volume_list = openstack_srv_volume_list)
-                if vdu.state == 'active':
-                    try:
-                        console_info = drv.nova_server_console(vdu.vdu_id)
-                    except Exception as e:
-                        pass
-                    else:
-                        vdu.console_url = console_info['console']['url']
-                        pass
-                vnf_resources.vdu_info_list.append(vdu)
-            return vnf_resources
+                    prev_vm_id = path.vnfr_ids[0].vdu_list[0].vm_id
+                    port_list.append((path.vnfr_ids[0].vdu_list[0].port_id,path.vnfr_ids[0].vdu_list[0].port_id))
+            vnffg_id = drv.create_port_chain(vnffg.name,port_list)
+            return vnffg_id
+
+    @rwstatus
+    def do_terminate_vnffg_chain(self, account,vnffg_id):
+        """
+        Terminate Service Function chain in ODL
+
+        @param account - a SDN account
+        """
+        self.log.debug('Received terminate VNFFG chain for id %s ', vnffg_id)
+        with self._use_driver(account) as drv:
+            drv.delete_port_chain(vnffg_id)
+
+    @rwstatus(ret_on_failure=[None])
+    def do_create_vnffg_classifier(self, account, vnffg_classifier):
+        """
+           Add VNFFG Classifier 
+
+           @param account - a SDN account
+        """
+        self.log.debug('Received Create VNFFG classifier for account {}, classifier {}'.format(account,vnffg_classifier))
+        protocol_map = {1:'ICMP',6:'TCP',17:'UDP'}
+        flow_classifier_list = list()
+        with self._use_driver(account) as drv:
+            for rule in vnffg_classifier.match_attributes:
+                classifier_name = vnffg_classifier.name + '_' + rule.name
+                flow_dict = {} 
+                for field, value in rule.as_dict().items():
+                    if field == 'ip_proto':
+                        flow_dict['protocol'] = protocol_map.get(value,None)
+                    elif field == 'source_ip_address':
+                        flow_dict['source_ip_prefix'] = value
+                    elif field == 'destination_ip_address':
+                        flow_dict['destination_ip_prefix'] = value
+                    elif field == 'source_port':
+                        flow_dict['source_port_range_min'] = value
+                        flow_dict['source_port_range_max'] = value
+                    elif field == 'destination_port':
+                        flow_dict['destination_port_range_min'] = value
+                        flow_dict['destination_port_range_max'] = value
+                if vnffg_classifier.has_field('port_id'):
+                    flow_dict['logical_source_port'] = vnffg_classifier.port_id 
+                flow_classifier_id = drv.create_flow_classifer(classifier_name, flow_dict)
+                flow_classifier_list.append(flow_classifier_id)
+            drv.update_port_chain(vnffg_classifier.rsp_id,flow_classifier_list)
+        return flow_classifier_list
+
+    @rwstatus(ret_on_failure=[None])
+    def do_terminate_vnffg_classifier(self, account, vnffg_classifier_list):
+        """
+           Add VNFFG Classifier 
+
+           @param account - a SDN account
+        """
+        self.log.debug('Received terminate VNFFG classifier for id %s ', vnffg_classifier_list)
+        with self._use_driver(account) as drv:
+            for classifier_id in vnffg_classifier_list:
+                drv.delete_flow_classifier(classifier_id)
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_vnffg_rendered_paths(self, account):
+        """
+           Get ODL Rendered Service Path List (SFC)
+
+           @param account - a SDN account
+        """
+        self.log.debug('Received get VNFFG rendered path for account %s ', account)
+        vnffg_rsps = RwsdnYang.VNFFGRenderedPaths() 
+        with self._use_driver(account) as drv:
+            port_chain_list = drv.get_port_chain_list()
+            for port_chain in port_chain_list:
+                #rsp = vnffg_rsps.vnffg_rendered_path.add()
+                #rsp.name = port_chain['name']
+                pass
+        return vnffg_rsps