CAL and SDNAL cleanup for failure cases in accounts
[osm/SO.git] / rwcal / plugins / vala / rwcal_openstack / rwcal_openstack.py
index 8e0c710..68702bb 100644 (file)
@@ -1,5 +1,5 @@
 
-# 
+#
 #   Copyright 2016 RIFT.IO Inc
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   limitations under the License.
 #
 
-import contextlib
 import logging
 import os
 import subprocess
-import uuid
+import tempfile
+import yaml
+
+import gi
+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
+
 
 from gi.repository import (
     GObject,
@@ -33,18 +39,16 @@ from gi.repository import (
     RwTypes,
     RwcalYang)
 
-PREPARE_VM_CMD = "prepare_vm.py --auth_url {auth_url} --username {username} --password {password} --tenant_name {tenant_name} --mgmt_network {mgmt_network} --server_id {server_id} --port_metadata"
+PREPARE_VM_CMD = "prepare_vm.py --auth_url {auth_url} --username {username} --password {password} --tenant_name {tenant_name} --region {region} --user_domain {user_domain} --project_domain {project_domain} --mgmt_network {mgmt_network} --server_id {server_id} --port_metadata "
 
-rwstatus_exception_map = { IndexError: RwTypes.RwStatus.NOTFOUND,
-                           KeyError: RwTypes.RwStatus.NOTFOUND,
-                           NotImplementedError: RwTypes.RwStatus.NOT_IMPLEMENTED,}
+rwstatus_exception_map = {IndexError: RwTypes.RwStatus.NOTFOUND,
+                          KeyError: RwTypes.RwStatus.NOTFOUND,
+                          NotImplementedError: RwTypes.RwStatus.NOT_IMPLEMENTED, }
 
 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
 
@@ -60,6 +64,22 @@ 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 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."""
 
@@ -67,41 +87,51 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
 
     def __init__(self):
         GObject.Object.__init__(self)
-        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 _get_account_key(self, account):
+        key = str()
+        for f in account.openstack.fields:
+            try:
+                key+= str(getattr(account.openstack, f))
+            except:
+                pass
+        key += account.name
+        return key
+    
     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("RwcalOpenstackPlugin: OpenstackDriver init failed. Exception: %s" %(str(e)))
-                raise
-
-            yield drv
-
+        acct_key = self._get_account_key(account)
+        
+        if acct_key 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[acct_key].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
 
@@ -118,18 +148,11 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             Validation Code and Details String
         """
         status = RwcalYang.CloudConnectionStatus()
-
         try:
-            with self._use_driver(account) as drv:
-                drv.validate_account_creds()
-
-        except openstack_drv.ValidationError as e:
-            self.log.error("RwcalOpenstackPlugin: OpenstackDriver credential validation failed. Exception: %s", str(e))
-            status.status = "failure"
-            status.details = "Invalid Credentials: %s" % str(e)
-
+            drv = self._use_driver(account) 
+            drv.validate_account_creds()
         except Exception as e:
-            msg = "RwcalOpenstackPlugin: OpenstackDriver connection failed. Exception: %s" %(str(e))
+            msg = "RwcalOpenstackPlugin: Exception: %s" %(str(e))
             self.log.error(msg)
             status.status = "failure"
             status.details = msg
@@ -233,42 +256,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
 
@@ -280,36 +300,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.
@@ -321,10 +319,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])
@@ -338,10 +340,17 @@ 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=[""])
     def do_create_vm(self, account, vminfo):
         """Create a new virtual machine.
@@ -353,21 +362,18 @@ 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
-        kwargs['image_id']  = vminfo.image_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
-            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
-                else:
-                    pool_name = None
-                floating_ip = self._allocate_floating_ip(drv, pool_name)
-            else:
-                floating_ip = None
+        ### If floating_ip is required and we don't have one, better fail before any further allocation
+        floating_ip = False
+        if vminfo.has_field('allocate_public_address') and vminfo.allocate_public_address:
+            floating_ip = True
 
         if vminfo.has_field('cloud_init') and vminfo.cloud_init.has_field('userdata'):
             kwargs['userdata']  = vminfo.cloud_init.userdata
@@ -403,14 +409,14 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             kwargs['availability_zone'] = None
 
         if vminfo.has_field('server_group'):
-            kwargs['scheduler_hints'] = {'group': vminfo.server_group }
+            kwargs['scheduler_hints'] = {'group': vminfo.server_group}
         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
 
@@ -422,8 +428,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):
@@ -433,8 +439,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):
@@ -444,8 +450,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):
@@ -455,8 +461,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):
@@ -482,7 +488,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']
@@ -502,10 +508,10 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             if key in vm.user_tags.fields:
                 setattr(vm.user_tags, key, value)
         if 'OS-EXT-SRV-ATTR:host' in vm_info:
-            if vm_info['OS-EXT-SRV-ATTR:host'] != None:
+            if vm_info['OS-EXT-SRV-ATTR:host'] is not None:
                 vm.host_name = vm_info['OS-EXT-SRV-ATTR:host']
         if 'OS-EXT-AZ:availability_zone' in vm_info:
-            if vm_info['OS-EXT-AZ:availability_zone'] != None:
+            if vm_info['OS-EXT-AZ:availability_zone'] is not None:
                 vm.availability_zone = vm_info['OS-EXT-AZ:availability_zone']
         return vm
 
@@ -520,8 +526,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
@@ -537,159 +543,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) 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)
-            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):
@@ -702,14 +559,18 @@ 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)
+        try:
+            flavor_id = 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))
+        except Exception as e:
+            self.log.error("Encountered exceptions during Flavor creation. Exception: %s", str(e))
+            raise
+            
+        return flavor_id  
 
     @rwstatus
     def do_delete_flavor(self, account, flavor_id):
@@ -719,146 +580,12 @@ 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 = self._use_driver(account)
+        try:
             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)
-
-                numa_node.vcpu = [ int(x) for x in flavor_info['extra_specs'][attr].split(',') ]
-
-            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
+        except Exception as e:
+            self.log.error("Encountered exceptions during Flavor deletion. Exception: %s", str(e))
+            raise
 
 
     @rwstatus(ret_on_failure=[[]])
@@ -872,10 +599,15 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
             List of flavors
         """
         response = RwcalYang.VimResources()
-        with self._use_driver(account) as drv:
+        drv = self._use_driver(account)
+        try:
             flavors = drv.nova_flavor_list()
-        for flv in flavors:
-            response.flavorinfo_list.append(RwcalOpenstackPlugin._fill_flavor_info(flv))
+            for flv in flavors:
+                response.flavorinfo_list.append(drv.utils.flavor.parse_flavor_info(flv))
+        except Exception as e:
+            self.log.error("Encountered exceptions during get-flavor-list. Exception: %s", str(e))
+            raise
+
         return response
 
     @rwstatus(ret_on_failure=[None])
@@ -889,9 +621,15 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             Flavor info item
         """
-        with self._use_driver(account) as drv:
+        drv = self._use_driver(account)
+        try:
             flavor = drv.nova_flavor_get(id)
-        return RwcalOpenstackPlugin._fill_flavor_info(flavor)
+            response = drv.utils.flavor.parse_flavor_info(flavor)
+        except Exception as e:
+            self.log.error("Encountered exceptions during get-flavor. Exception: %s", str(e))
+            raise
+        
+        return response
 
 
     def _fill_network_info(self, network_info, account):
@@ -910,7 +648,7 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         network                  = RwcalYang.NetworkInfoItem()
         network.network_name     = network_info['name']
         network.network_id       = network_info['id']
-        if ('provider:network_type' in network_info) and (network_info['provider:network_type'] != None):
+        if ('provider:network_type' in network_info) and (network_info['provider:network_type'] is not None):
             network.provider_network.overlay_type = network_info['provider:network_type'].upper()
         if ('provider:segmentation_id' in network_info) and (network_info['provider:segmentation_id']):
             network.provider_network.segmentation_id = network_info['provider:segmentation_id']
@@ -919,8 +657,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
 
@@ -935,8 +673,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
@@ -952,8 +690,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=[""])
@@ -967,6 +705,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
@@ -981,10 +722,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
@@ -995,8 +736,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):
@@ -1034,9 +775,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=[[]])
@@ -1050,8 +790,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
@@ -1067,6 +807,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
@@ -1078,8 +821,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):
@@ -1089,8 +832,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):
@@ -1140,129 +883,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 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(vm_info, flavor_info, mgmt_network, port_list, server_group):
-        """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
-        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)
-        return vdu
 
     @rwcalstatus(ret_on_failure=[""])
     def do_create_virtual_link(self, account, link_params):
@@ -1273,73 +893,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)
-
-            if link_params.ip_profile_params.has_field('gateway_address'):
-                kwargs['gateway_ip'] = link_params.ip_profile_params.gateway_address
-                
+        
+        drv = self._use_driver(account)
+        try:
+            kwargs = drv.utils.network.make_virtual_link_args(link_params)
+            network_id = drv.neutron_network_create(**kwargs)
+            kwargs = drv.utils.network.make_subnet_args(link_params, network_id)
             drv.neutron_subnet_create(**kwargs)
-            
+        except Exception as e:
+            self.log.error("Encountered exceptions during network creation. Exception: %s", str(e))
+            raise
+
         return network_id
 
 
@@ -1354,17 +920,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):
@@ -1377,22 +942,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):
@@ -1405,432 +968,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':
-            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.port_type))
-
-        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)
-        """
+        except Exception as e:
+            self.log.exception("Exception %s occured during virtual-link-list-get", str(e))
+            raise
+        return vnf_resources
 
-        # 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
 
     @rwcalstatus(ret_on_failure=[""])
     def do_create_vdu(self, account, vdu_init):
@@ -1843,124 +997,46 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             The vdu_id
         """
-        ### First create required number of ports aka connection points
-        with self._use_driver(account) as drv:
-            ### If floating_ip is required and we don't have one, better fail before any further allocation
-            if vdu_init.has_field('allocate_public_address') and vdu_init.allocate_public_address:
-                if account.openstack.has_field('floating_ip_pool'):
-                    pool_name = account.openstack.floating_ip_pool
-                else:
-                    pool_name = None
-                floating_ip = self._allocate_floating_ip(drv, pool_name)
-            else:
-                floating_ip = None
-
-        port_list = []
-        network_list = []
-        for c_point in vdu_init.connection_points:
-            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)
-
-        with self._use_driver(account) as drv:
-            ### Now Create VM
-            vm           = RwcalYang.VMInfoItem()
-            vm.vm_name   = vdu_init.name
-            vm.flavor_id = vdu_init.flavor_id
-            vm.image_id  = vdu_init.image_id
-            vm_network   = vm.network_list.add()
-            vm_network.network_id = drv._mgmt_network_id
-            if vdu_init.has_field('vdu_init') and vdu_init.vdu_init.has_field('userdata'):
-                vm.cloud_init.userdata = vdu_init.vdu_init.userdata
-
-            if vdu_init.has_field('node_id'):
-                vm.user_tags.node_id   = vdu_init.node_id;
-
-            if vdu_init.has_field('availability_zone') and vdu_init.availability_zone.has_field('name'):
-                vm.availability_zone = vdu_init.availability_zone.name
-
-            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]))
-                vm.server_group = group_id[0]
-
-            for port_id in port_list:
-                port = vm.port_list.add()
-                port.port_id = port_id
-
-            pci_assignement = self.prepare_vpci_metadata(drv, vdu_init)
-            if pci_assignement != '':
-                vm.user_tags.pci_assignement = pci_assignement
-
-            vm_id = self.do_create_vm(account, vm, no_rwstatus=True)
-            self.prepare_vdu_on_boot(account, vm_id, floating_ip)
-            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):
-        cmd = PREPARE_VM_CMD.format(auth_url     = account.openstack.auth_url,
-                                    username     = account.openstack.key,
-                                    password     = account.openstack.secret,
-                                    tenant_name  = account.openstack.tenant,
-                                    mgmt_network = account.openstack.mgmt_network,
-                                    server_id    = server_id)
-
-        if floating_ip is not None:
-            cmd += (" --floating_ip "+ floating_ip.ip)
+        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
+    
 
+    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,
+                                    tenant_name    = account.openstack.tenant,
+                                    region         = account.openstack.region,
+                                    user_domain    = account.openstack.user_domain,
+                                    project_domain = account.openstack.project_domain,
+                                    mgmt_network   = account.openstack.mgmt_network,
+                                    server_id      = server_id)
+        vol_list = list()
+        
+        if vdu_params.has_field('allocate_public_address') and vdu_params.allocate_public_address:
+            cmd += " --floating_ip"
+            if account.openstack.has_field('floating_ip_pool'):
+                cmd += (" --pool_name " + account.openstack.floating_ip_pool)
+        
+        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
+        exec_cmd = exec_path + '/' + cmd
         self.log.info("Running command: %s" %(exec_cmd))
         subprocess.call(exec_cmd, shell=True)
 
@@ -1972,6 +1048,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 = []
@@ -1983,18 +1060,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
@@ -2008,25 +1084,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):
@@ -2039,37 +1104,15 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud):
         Returns:
             Object of type RwcalYang.VDUInfoParams
         """
-        with self._use_driver(account) as drv:
-
-            ### Get list of ports excluding the one for management network
-            port_list = [p for p in drv.neutron_port_list(**{'device_id': vdu_id}) if p['network_id'] != drv.get_mgmt_network_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']]
-            vdu_info = RwcalOpenstackPlugin._fill_vdu_info(vm,
-                                                           flavor_info,
-                                                           account.openstack.mgmt_network,
-                                                           port_list,
-                                                           server_group)
-            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])
@@ -2083,40 +1126,15 @@ 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:
-                ### Get list of ports excluding one for management network
-                port_list = [p for p in drv.neutron_port_list(**{'device_id': vm['id']}) if p['network_id'] != drv.get_mgmt_network_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)))
-
-                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']]
-
-                vdu = RwcalOpenstackPlugin._fill_vdu_info(vm,
-                                                          flavor_info,
-                                                          account.openstack.mgmt_network,
-                                                          port_list,
-                                                          server_group)
-                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
+                vdu = drv.utils.compute.parse_cloud_vdu_info(vm)
                 vnf_resources.vdu_info_list.append(vdu)
-            return vnf_resources
+        except Exception as e:
+            self.log.exception("Exception %s occured during get-vdu-list", str(e))
+            raise
+        return vnf_resources