Merge from OSM SO master
[osm/SO.git] / rwlaunchpad / plugins / rwvnfm / rift / tasklets / rwvnfmtasklet / rwvnfmtasklet.py
index d359aa4..253094f 100755 (executable)
@@ -49,7 +49,13 @@ from gi.repository import (
 import rift.tasklets
 import rift.package.store
 import rift.package.cloud_init
+import rift.package.script
 import rift.mano.dts as mano_dts
+from rift.mano.utils.project import (
+    ManoProject,
+    ProjectHandler,
+    )
+import rift.mano.utils.short_name as mano_short_name
 
 
 class VMResourceError(Exception):
@@ -161,7 +167,8 @@ class VDURecordState(enum.Enum):
 
 class VcsComponent(object):
     """ VCS Component within the VNF descriptor """
-    def __init__(self, dts, log, loop, cluster_name, vcs_handler, component, mangled_name):
+    def __init__(self, dts, log, loop, cluster_name,
+                 vcs_handler, component, mangled_name):
         self._dts = dts
         self._log = log
         self._loop = loop
@@ -183,7 +190,7 @@ class VcsComponent(object):
     @property
     def path(self):
         """ The path for this object """
-        return("D,/rw-manifest:manifest" +
+        return ("D,/rw-manifest:manifest" +
                "/rw-manifest:operational-inventory" +
                "/rw-manifest:component" +
                "[rw-manifest:component-name = '{}']").format(self.name)
@@ -268,8 +275,10 @@ class VirtualDeploymentUnitRecord(object):
                  dts,
                  log,
                  loop,
+                 project,
                  vdud,
                  vnfr,
+                 nsr_config,
                  mgmt_intf,
                  mgmt_network,
                  cloud_account_name,
@@ -279,8 +288,10 @@ class VirtualDeploymentUnitRecord(object):
         self._dts = dts
         self._log = log
         self._loop = loop
+        self._project = project
         self._vdud = vdud
         self._vnfr = vnfr
+        self._nsr_config = nsr_config
         self._mgmt_intf = mgmt_intf
         self._cloud_account_name = cloud_account_name
         self._vnfd_package_store = vnfd_package_store
@@ -297,7 +308,8 @@ class VirtualDeploymentUnitRecord(object):
         self._rm_regh = None
         self._vm_resp = None
         self._vdud_cloud_init = None
-        self._vdur_console_handler = VnfrConsoleOperdataDtsHandler(dts, log, loop, self._vnfr._vnfm, self._vnfr.vnfr_id, self._vdur_id,self.vdu_id)
+        self._vdur_console_handler = VnfrConsoleOperdataDtsHandler(
+            dts, log, loop, self._vnfr._vnfm, self._vnfr.vnfr_id, self._vdur_id,self.vdu_id)
 
     @asyncio.coroutine
     def vdu_opdata_register(self):
@@ -340,6 +352,31 @@ class VirtualDeploymentUnitRecord(object):
         """ Return this VDUR's name """
         return self._name
 
+    # Truncated name confirming to RFC 1123
+    @property
+    def unique_short_name(self):
+        """ Return this VDUR's unique short name """
+        # Impose these restrictions on Unique name
+        #  Max 64
+        #    - Max 10 of NSR name (remove all specialcharacters, only numbers and alphabets)
+        #    - 6 chars of shortened name
+        #    - Max 10 of VDU name (remove all specialcharacters, only numbers and alphabets)
+        #
+        def _restrict_tag(input_str):
+           # Exclude all characters except a-zA-Z0-9
+           outstr = re.sub('[^a-zA-Z0-9]', '', input_str)
+           # Take max of 10 chars
+           return outstr[-10:]
+
+        # Use NSR name for part1
+        part1 = _restrict_tag(self._nsr_config.name)
+        # Get unique short string (6 chars)
+        part2 = mano_short_name.StringShortner(self._name)
+        # Use VDU ID for part3
+        part3 = _restrict_tag(self._vdud.id)
+        shortstr = part1 + "-" + part2.short_string + "-" + part3
+        return shortstr
+
     @property
     def cloud_account_name(self):
         """ Cloud account this VDU should be created in """
@@ -384,21 +421,24 @@ class VirtualDeploymentUnitRecord(object):
 
     @property
     def msg(self):
-        """ VDU message """
+        """ Process VDU message from resmgr"""
         vdu_fields = ["vm_flavor",
                       "guest_epa",
                       "vswitch_epa",
                       "hypervisor_epa",
                       "host_epa",
                       "volumes",
-                      "name"]
+                      ]
         vdu_copy_dict = {k: v for k, v in
                          self._vdud.as_dict().items() if k in vdu_fields}
         vdur_dict = {"id": self._vdur_id,
                      "vdu_id_ref": self._vdud.id,
                      "operational_status": self.operational_status,
                      "operational_status_details": self._state_failed_reason,
+                     "name": self.name,
+                     "unique_short_name": self.unique_short_name
                      }
+
         if self.vm_resp is not None:
             vdur_dict.update({"vim_id": self.vm_resp.vdu_id,
                               "flavor_id": self.vm_resp.flavor_id
@@ -420,6 +460,26 @@ class VirtualDeploymentUnitRecord(object):
                     vdurvol_data = [vduvol for vduvol in vdur_dict['volumes'] if vduvol['name'] == opvolume.name]
                     if len(vdurvol_data) == 1:
                        vdurvol_data[0]["volume_id"] = opvolume.volume_id
+                       if opvolume.has_field('custom_meta_data'):
+                           metadata_list = list()
+                           for metadata_item in opvolume.custom_meta_data:
+                               metadata_list.append(metadata_item.as_dict())
+                           vdurvol_data[0]['custom_meta_data'] = metadata_list
+
+            if self._vm_resp.has_field('supplemental_boot_data'):
+                vdur_dict['supplemental_boot_data'] = dict()
+                if self._vm_resp.supplemental_boot_data.has_field('boot_data_drive'):
+                    vdur_dict['supplemental_boot_data']['boot_data_drive'] = self._vm_resp.supplemental_boot_data.boot_data_drive
+                if self._vm_resp.supplemental_boot_data.has_field('custom_meta_data'):
+                    metadata_list = list()
+                    for metadata_item in self._vm_resp.supplemental_boot_data.custom_meta_data:
+                       metadata_list.append(metadata_item.as_dict())
+                    vdur_dict['supplemental_boot_data']['custom_meta_data'] = metadata_list
+                if self._vm_resp.supplemental_boot_data.has_field('config_file'):
+                    file_list = list()
+                    for file_item in self._vm_resp.supplemental_boot_data.config_file:
+                       file_list.append(file_item.as_dict())
+                    vdur_dict['supplemental_boot_data']['config_file'] = file_list
 
         icp_list = []
         ii_list = []
@@ -443,13 +503,13 @@ class VirtualDeploymentUnitRecord(object):
 
         ei_list = []
         for intf, cp, vlr in self._ext_intf:
-            ei_list.append({"name": cp,
-                            "vnfd_connection_point_ref": cp,
+            ei_list.append({"name": cp.name,
+                            "vnfd_connection_point_ref": cp.name,
                             "virtual_interface": {}})
-            self._vnfr.update_cp(cp,
-                                 self.cp_ip_addr(cp),
-                                 self.cp_mac_addr(cp),
-                                 self.cp_id(cp))
+            self._vnfr.update_cp(cp.name,
+                                 self.cp_ip_addr(cp.name),
+                                 self.cp_mac_addr(cp.name),
+                                 self.cp_id(cp.name))
 
         vdur_dict["external_interface"] = ei_list
 
@@ -458,14 +518,15 @@ class VirtualDeploymentUnitRecord(object):
             placement_groups.append(group.as_dict())
         vdur_dict['placement_groups_info'] = placement_groups
 
-        return RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur.from_dict(vdur_dict)
+        return RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_Vdur.from_dict(vdur_dict)
 
     @property
     def resmgr_path(self):
         """ path for resource-mgr"""
-        return ("D,/rw-resource-mgr:resource-mgmt" +
-                "/vdu-event" +
-                "/vdu-event-data[event-id='{}']".format(self._request_id))
+        xpath = self._project.add_project("D,/rw-resource-mgr:resource-mgmt" +
+                                          "/vdu-event" +
+                                          "/vdu-event-data[event-id='{}']".format(self._request_id))
+        return xpath
 
     @property
     def vm_flavor_msg(self):
@@ -500,6 +561,7 @@ class VirtualDeploymentUnitRecord(object):
             try:
                 return cloud_init_extractor.read_script(stored_package, filename)
             except rift.package.cloud_init.CloudInitExtractionError as e:
+                self.instantiation_failed(str(e))
                 raise VirtualDeploymentUnitRecordError(e)
         else:
             self._log.debug("VDU Instantiation: cloud-init script not provided")
@@ -519,15 +581,19 @@ class VirtualDeploymentUnitRecord(object):
 
         if availability_zones:
             if len(availability_zones) > 1:
-                self._log.error("Can not launch VDU: %s in multiple availability zones. Requested Zones: %s", self.name, availability_zones)
-                raise VNFMPlacementGroupError("Can not launch VDU: {} in multiple availability zones. Requsted Zones".format(self.name, availability_zones))
+                self._log.error("Can not launch VDU: %s in multiple availability zones. " +
+                                "Requested Zones: %s", self.name, availability_zones)
+                raise VNFMPlacementGroupError("Can not launch VDU: {} in multiple availability" +
+                                              " zones. Requsted Zones".format(self.name, availability_zones))
             else:
                 vm_create_msg_dict['availability_zone'] = availability_zones[0]
 
         if server_groups:
             if len(server_groups) > 1:
-                self._log.error("Can not launch VDU: %s in multiple Server Group. Requested Groups: %s", self.name, server_groups)
-                raise VNFMPlacementGroupError("Can not launch VDU: {} in multiple Server Groups. Requsted Groups".format(self.name, server_groups))
+                self._log.error("Can not launch VDU: %s in multiple Server Group. " +
+                                "Requested Groups: %s", self.name, server_groups)
+                raise VNFMPlacementGroupError("Can not launch VDU: {} in multiple " +
+                                              "Server Groups. Requsted Groups".format(self.name, server_groups))
             else:
                 vm_create_msg_dict['server_group'] = server_groups[0]
 
@@ -552,18 +618,44 @@ class VirtualDeploymentUnitRecord(object):
             self._log.info("Ignoring placement group with cloud construct for cloud-type: %s", cloud_type)
         return
 
+    def process_custom_bootdata(self, vm_create_msg_dict):
+        """Process the custom boot data"""
+        if 'config_file' not in vm_create_msg_dict['supplemental_boot_data']:
+            return
+
+        self._vnfd_package_store.refresh()
+        stored_package = self._vnfd_package_store.get_package(self._vnfr.vnfd_id)
+        cloud_init_extractor = rift.package.cloud_init.PackageCloudInitExtractor(self._log)
+        for file_item in vm_create_msg_dict['supplemental_boot_data']['config_file']:
+            if 'source' not in file_item or 'dest' not in file_item:
+                continue
+            source = file_item['source']
+            # Find source file in scripts dir of VNFD
+            self._log.debug("Checking for source config file at %s", source)
+            try:
+               source_file_str = cloud_init_extractor.read_script(stored_package, source)
+            except rift.package.cloud_init.CloudInitExtractionError as e:
+               raise  VirtualDeploymentUnitRecordError(e)
+            # Update source file location with file contents
+            file_item['source'] = source_file_str
+
+        return
+
     def resmgr_msg(self, config=None):
         vdu_fields = ["vm_flavor",
                       "guest_epa",
                       "vswitch_epa",
                       "hypervisor_epa",
-                      "host_epa"]
+                      "host_epa",
+                      "volumes",
+                      "supplemental_boot_data"]
 
         self._log.debug("Creating params based on VDUD: %s", self._vdud)
         vdu_copy_dict = {k: v for k, v in self._vdud.as_dict().items() if k in vdu_fields}
 
         vm_create_msg_dict = {
-                "name": self.name,
+                "name": self.unique_short_name, # Truncated name confirming to RFC 1123
+                "node_id": self.name,           # Rift assigned Id
                 }
 
         if self.image_name is not None:
@@ -585,9 +677,12 @@ class VirtualDeploymentUnitRecord(object):
 
         cp_list = []
         for intf, cp, vlr in self._ext_intf:
-            cp_info = {"name": cp,
-                       "virtual_link_id": vlr.network_id,
-                       "type_yang": intf.virtual_interface.type_yang}
+            cp_info = { "name": cp.name,
+                        "virtual_link_id": vlr.network_id,
+                        "type_yang": intf.virtual_interface.type_yang }
+
+            if cp.has_field('port_security_enabled'):
+                cp_info["port_security_enabled"] = cp.port_security_enabled
 
             if (intf.virtual_interface.has_field('vpci') and
                     intf.virtual_interface.vpci is not None):
@@ -606,23 +701,29 @@ class VirtualDeploymentUnitRecord(object):
                                 "type_yang": intf.virtual_interface.type_yang,
                                 "vpci": intf.virtual_interface.vpci})
             else:
-                cp_list.append({"name": cp,
-                                "virtual_link_id": vlr.network_id,
-                                "type_yang": intf.virtual_interface.type_yang})
+                if cp.has_field('port_security_enabled'):
+                    cp_list.append({"name": cp,
+                                    "virtual_link_id": vlr.network_id,
+                                    "type_yang": intf.virtual_interface.type_yang,
+                                    "port_security_enabled": cp.port_security_enabled})
+                else:
+                    cp_list.append({"name": cp,
+                                    "virtual_link_id": vlr.network_id,
+                                    "type_yang": intf.virtual_interface.type_yang})
+
 
         vm_create_msg_dict["connection_points"] = cp_list
         vm_create_msg_dict.update(vdu_copy_dict)
 
         self.process_placement_groups(vm_create_msg_dict)
+        if 'supplemental_boot_data' in vm_create_msg_dict:
+             self.process_custom_bootdata(vm_create_msg_dict) 
 
         msg = RwResourceMgrYang.VDUEventData()
         msg.event_id = self._request_id
         msg.cloud_account = self.cloud_account_name
         msg.request_info.from_dict(vm_create_msg_dict)
 
-        for volume in self._vdud.volumes:
-            v = msg.request_info.volumes.add()
-            v.from_dict(volume.as_dict())
         return msg
 
     @asyncio.coroutine
@@ -646,7 +747,7 @@ class VirtualDeploymentUnitRecord(object):
             self._rm_regh = None
 
         if self._vdur_console_handler is not None:
-            self._log.error("Deregistering vnfr vdur registration handle")
+            self._log.debug("Deregistering vnfr vdur registration handle")
             self._vdur_console_handler._regh.deregister()
             self._vdur_console_handler._regh = None
 
@@ -734,7 +835,7 @@ class VirtualDeploymentUnitRecord(object):
 
             vlr = vnfr.ext_vlr_by_id(cp.vlr_ref)
 
-            etuple = (ext_intf, cp.name, vlr)
+            etuple = (ext_intf, cp, vlr)
             self._ext_intf.append(etuple)
 
             self._log.debug("Created external interface tuple  : %s", etuple)
@@ -895,8 +996,8 @@ class VirtualDeploymentUnitRecord(object):
 
             vm_resp = yield from self.create_resource(xact, vnfr, config)
             self._vm_resp = vm_resp
-
             self._state = VDURecordState.RESOURCE_ALLOC_PENDING
+
             self._log.debug("Requested VM from resource manager response %s",
                             vm_resp)
             if vm_resp.resource_state == "active":
@@ -939,13 +1040,16 @@ class VlRecordState(enum.Enum):
 
 class InternalVirtualLinkRecord(object):
     """ Internal Virtual Link record """
-    def __init__(self, dts, log, loop, ivld_msg, vnfr_name, cloud_account_name):
+    def __init__(self, dts, log, loop, project,
+                 ivld_msg, vnfr_name, cloud_account_name, ip_profile=None):
         self._dts = dts
         self._log = log
         self._loop = loop
+        self._project = project
         self._ivld_msg = ivld_msg
         self._vnfr_name = vnfr_name
         self._cloud_account_name = cloud_account_name
+        self._ip_profile = ip_profile
 
         self._vlr_req = self.create_vlr()
         self._vlr = None
@@ -959,7 +1063,10 @@ class InternalVirtualLinkRecord(object):
     @property
     def name(self):
         """ Name of this VL """
-        return self._vnfr_name + "." + self._ivld_msg.name
+        if self._ivld_msg.vim_network_name:
+            return self._ivld_msg.vim_network_name
+        else:
+            return self._vnfr_name + "." + self._ivld_msg.name
 
     @property
     def network_id(self):
@@ -968,7 +1075,8 @@ class InternalVirtualLinkRecord(object):
 
     def vlr_path(self):
         """ VLR path for this VLR instance"""
-        return "D,/vlr:vlr-catalog/vlr:vlr[vlr:id = '{}']".format(self.vlr_id)
+        return self._project.add_project("D,/vlr:vlr-catalog/vlr:vlr[vlr:id = '{}']".
+                                         format(self.vlr_id))
 
     def create_vlr(self):
         """ Create the VLR record which will be instantiated """
@@ -978,6 +1086,7 @@ class InternalVirtualLinkRecord(object):
                       "description",
                       "version",
                       "type_yang",
+                      "vim_network_name",
                       "provider_network"]
 
         vld_copy_dict = {k: v for k, v in self._ivld_msg.as_dict().items() if k in vld_fields}
@@ -986,9 +1095,13 @@ class InternalVirtualLinkRecord(object):
                     "name": self.name,
                     "cloud_account": self._cloud_account_name,
                     }
+
+        if self._ip_profile and self._ip_profile.has_field('ip_profile_params'):
+            vlr_dict['ip_profile_params' ] = self._ip_profile.ip_profile_params.as_dict()
+
         vlr_dict.update(vld_copy_dict)
 
-        vlr = RwVlrYang.YangData_Vlr_VlrCatalog_Vlr.from_dict(vlr_dict)
+        vlr = RwVlrYang.YangData_RwProject_Project_VlrCatalog_Vlr.from_dict(vlr_dict)
         return vlr
 
     @asyncio.coroutine
@@ -1085,6 +1198,7 @@ class VirtualNetworkFunctionRecord(object):
         self._dts = dts
         self._log = log
         self._loop = loop
+        self._project = vnfm._project
         self._cluster_name = cluster_name
         self._vnfr_msg = vnfr_msg
         self._vnfr_id = vnfr_msg.id
@@ -1137,7 +1251,8 @@ class VirtualNetworkFunctionRecord(object):
     @staticmethod
     def vnfd_xpath(vnfd_id):
         """ VNFD xpath associated with this VNFR """
-        return "C,/vnfd:vnfd-catalog/vnfd:vnfd[vnfd:id = '{}']".format(vnfd_id)
+        return ("C,/project-vnfd:vnfd-catalog/project-vnfd:vnfd[project-vnfd:id = '{}']".
+                format(vnfd_id))
 
     @property
     def vnfd_ref_count(self):
@@ -1218,7 +1333,7 @@ class VirtualNetworkFunctionRecord(object):
     def get_nsr_config(self):
         ### Need access to NS instance configuration for runtime resolution.
         ### This shall be replaced when deployment flavors are implemented
-        xpath = "C,/nsr:ns-instance-config"
+        xpath = self._project.add_project("C,/nsr:ns-instance-config")
         results = yield from self._dts.query_read(xpath, rwdts.XactFlag.MERGE)
 
         for result in results:
@@ -1268,7 +1383,7 @@ class VirtualNetworkFunctionRecord(object):
         vnfd_fields = ["short_name", "vendor", "description", "version"]
         vnfd_copy_dict = {k: v for k, v in self.vnfd.as_dict().items() if k in vnfd_fields}
 
-        mgmt_intf = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_MgmtInterface()
+        mgmt_intf = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_MgmtInterface()
         ip_address, port = self.mgmt_intf_info()
 
         if ip_address is not None:
@@ -1288,8 +1403,8 @@ class VirtualNetworkFunctionRecord(object):
 
         vnfr_dict.update(vnfd_copy_dict)
 
-        vnfr_msg = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.from_dict(vnfr_dict)
-        vnfr_msg.vnfd = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vnfd.from_dict(self.vnfd.as_dict())
+        vnfr_msg = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr.from_dict(vnfr_dict)
+        vnfr_msg.vnfd = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_Vnfd.from_dict(self.vnfd.as_dict())
 
         vnfr_msg.create_time = self._create_time
         vnfr_msg.uptime = int(time.time()) - self._create_time
@@ -1310,13 +1425,13 @@ class VirtualNetworkFunctionRecord(object):
             vnfr_msg.dashboard_url = self.dashboard_url
 
         for cpr in self._cprs:
-            new_cp = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_ConnectionPoint.from_dict(cpr.as_dict())
+            new_cp = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_ConnectionPoint.from_dict(cpr.as_dict())
             vnfr_msg.connection_point.append(new_cp)
 
         if self._vnf_mon is not None:
             for monp in self._vnf_mon.msg:
                 vnfr_msg.monitoring_param.append(
-                    VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_MonitoringParam.from_dict(monp.as_dict()))
+                    VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_MonitoringParam.from_dict(monp.as_dict()))
 
         if self._vnfr.vnf_configuration is not None:
             vnfr_msg.vnf_configuration.from_dict(self._vnfr.vnf_configuration.as_dict())
@@ -1325,7 +1440,7 @@ class VirtualNetworkFunctionRecord(object):
                 vnfr_msg.vnf_configuration.config_access.mgmt_ip_address = ip_address
 
         for group in self._vnfr_msg.placement_groups_info:
-            group_info = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_PlacementGroupsInfo()
+            group_info = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_PlacementGroupsInfo()
             group_info.from_dict(group.as_dict())
             vnfr_msg.placement_groups_info.append(group_info)
 
@@ -1355,7 +1470,7 @@ class VirtualNetworkFunctionRecord(object):
     @property
     def xpath(self):
         """ path for this  VNFR """
-        return("D,/vnfr:vnfr-catalog"
+        return self._project.add_project("D,/vnfr:vnfr-catalog"
                "/vnfr:vnfr[vnfr:id='{}']".format(self.vnfr_id))
 
     @asyncio.coroutine
@@ -1369,6 +1484,13 @@ class VirtualNetworkFunctionRecord(object):
         self._log.debug("Published VNFR path = [%s], record = [%s]",
                         self.xpath, self.msg)
 
+    def resolve_vld_ip_profile(self, vnfd_msg, vld):
+        self._log.debug("Receieved ip profile ref is %s",vld.ip_profile_ref)
+        if not vld.has_field('ip_profile_ref'):
+            return None
+        profile = [profile for profile in vnfd_msg.ip_profiles if profile.name == vld.ip_profile_ref]
+        return profile[0] if profile else None
+
     @asyncio.coroutine
     def create_vls(self):
         """ Publish The VLs associated with this VNF """
@@ -1384,7 +1506,8 @@ class VirtualNetworkFunctionRecord(object):
                                             loop=self._loop,
                                             ivld_msg=ivld_msg,
                                             vnfr_name=self.name,
-                                            cloud_account_name=self.cloud_account_name
+                                            cloud_account_name=self.cloud_account_name,
+                                            ip_profile=self.resolve_vld_ip_profile(self.vnfd, ivld_msg)
                                             )
             self._vlrs.append(vlr)
 
@@ -1422,7 +1545,7 @@ class VirtualNetworkFunctionRecord(object):
         for group_info in nsr_config.vnfd_placement_group_maps:
             if group_info.placement_group_ref == input_group.name and \
                group_info.vnfd_id_ref == self.vnfd_id:
-                group = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur_PlacementGroupsInfo()
+                group = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_Vdur_PlacementGroupsInfo()
                 group_dict = {k:v for k,v in
                               group_info.as_dict().items()
                               if (k != 'placement_group_ref' and k !='vnfd_id_ref')}
@@ -1433,28 +1556,26 @@ class VirtualNetworkFunctionRecord(object):
         return None
 
     @asyncio.coroutine
-    def get_vdu_placement_groups(self, vdu):
+    def get_vdu_placement_groups(self, vdu, nsr_config):
         placement_groups = []
         ### Step-1: Get VNF level placement groups
         for group in self._vnfr_msg.placement_groups_info:
-            #group_info = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur_PlacementGroupsInfo()
+            #group_info = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_Vdur_PlacementGroupsInfo()
             #group_info.from_dict(group.as_dict())
             placement_groups.append(group)
 
-        ### Step-2: Get NSR config. This is required for resolving placement_groups cloud constructs
-        nsr_config = yield from self.get_nsr_config()
-
-        ### Step-3: Get VDU level placement groups
+        ### Step-2: Get VDU level placement groups
         for group in self.vnfd.placement_groups:
             for member_vdu in group.member_vdus:
                 if member_vdu.member_vdu_ref == vdu.id:
                     group_info = self.resolve_placement_group_cloud_construct(group,
                                                                               nsr_config)
                     if group_info is None:
-                        self._log.info("Could not resolve cloud-construct for placement group: %s", group.name)
-                        ### raise VNFMPlacementGroupError("Could not resolve cloud-construct for placement group: {}".format(group.name))
+                        self._log.info("Could not resolve cloud-construct for " +
+                                       "placement group: %s", group.name)
                     else:
-                        self._log.info("Successfully resolved cloud construct for placement group: %s for VDU: %s in VNF: %s (Member Index: %s)",
+                        self._log.info("Successfully resolved cloud construct for " +
+                                       "placement group: %s for VDU: %s in VNF: %s (Member Index: %s)",
                                        str(group_info),
                                        vdu.name,
                                        self.vnf_name,
@@ -1463,6 +1584,10 @@ class VirtualNetworkFunctionRecord(object):
 
         return placement_groups
 
+    @asyncio.coroutine
+    def vdu_cloud_init_instantiation(self):
+        [vdu.vdud_cloud_init for vdu in self._vdus]
+
     @asyncio.coroutine
     def create_vdus(self, vnfr, restart_mode=False):
         """ Create the VDUs associated with this VNF """
@@ -1487,23 +1612,31 @@ class VirtualNetworkFunctionRecord(object):
 
 
         self._log.info("Creating VDU's for vnfd id: %s", self.vnfd_id)
+
+        # Get NSR config - Needed for placement groups and to derive VDU short-name
+        nsr_config = yield from self.get_nsr_config()
+
         for vdu in self._rw_vnfd.vdu:
             self._log.debug("Creating vdu: %s", vdu)
             vdur_id = get_vdur_id(vdu)
 
-            placement_groups = yield from self.get_vdu_placement_groups(vdu)
-            self._log.info("Launching VDU: %s from VNFD :%s (Member Index: %s) with Placement Groups: %s",
+
+            placement_groups = yield from self.get_vdu_placement_groups(vdu, nsr_config)
+            self._log.info("Launching VDU: %s from VNFD :%s (Member Index: %s) with Placement Groups: %s, Existing vdur_id %s",
                            vdu.name,
                            self.vnf_name,
                            self.member_vnf_index,
-                           [ group.name for group in placement_groups])
+                           [ group.name for group in placement_groups],
+                           vdur_id)
 
             vdur = VirtualDeploymentUnitRecord(
                 dts=self._dts,
                 log=self._log,
                 loop=self._loop,
+                project = self._project,
                 vdud=vdu,
                 vnfr=vnfr,
+                nsr_config=nsr_config,
                 mgmt_intf=self.has_mgmt_interface(vdu),
                 mgmt_network=self._mgmt_network,
                 cloud_account_name=self.cloud_account_name,
@@ -1527,8 +1660,8 @@ class VirtualNetworkFunctionRecord(object):
         vdu_id_pattern = re.compile(r"\{\{ vdu\[([^]]+)\]\S* \}\}")
 
         for vdu in self._vdus:
-            if vdu.vdud_cloud_init is not None:
-                for vdu_id in vdu_id_pattern.findall(vdu.vdud_cloud_init):
+            if vdu._vdud_cloud_init is not None:
+                for vdu_id in vdu_id_pattern.findall(vdu._vdud_cloud_init):
                     if vdu_id != vdu.vdu_id:
                         # This means that vdu.vdu_id depends upon vdu_id,
                         # i.e. vdu_id must be instantiated before
@@ -1556,7 +1689,6 @@ class VirtualNetworkFunctionRecord(object):
             # wait for the VDUR to enter a terminal state
             while vdu._state not in terminal:
                 yield from asyncio.sleep(1, loop=self._loop)
-
             # update the datastore
             datastore.update(vdu)
 
@@ -1649,8 +1781,7 @@ class VirtualNetworkFunctionRecord(object):
 
     def vlr_xpath(self, vlr_id):
         """ vlr xpath """
-        return(
-            "D,/vlr:vlr-catalog/"
+        return self._project.add_project("D,/vlr:vlr-catalog/"
             "vlr:vlr[vlr:id = '{}']".format(vlr_id))
 
     def ext_vlr_by_id(self, vlr_id):
@@ -1740,6 +1871,7 @@ class VirtualNetworkFunctionRecord(object):
     @asyncio.coroutine
     def instantiate(self, xact, restart_mode=False):
         """ instantiate this VNF """
+        self._log.info("Instantiate VNF {}: {}".format(self._vnfr_id, self._state))
         self.set_state(VirtualNetworkFunctionRecordState.VL_INIT_PHASE)
         self._rw_vnfd = yield from self._vnfm.fetch_vnfd(self._vnfd_id)
 
@@ -1751,11 +1883,11 @@ class VirtualNetworkFunctionRecord(object):
 
             def cpr_from_cp(cp):
                 """ Creates a record level connection point from the desciptor cp"""
-                cp_fields = ["name", "image", "vm-flavor"]
+                cp_fields = ["name", "image", "vm-flavor", "port_security_enabled"]
                 cp_copy_dict = {k: v for k, v in cp.as_dict().items() if k in cp_fields}
                 cpr_dict = {}
                 cpr_dict.update(cp_copy_dict)
-                return VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_ConnectionPoint.from_dict(cpr_dict)
+                return VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_ConnectionPoint.from_dict(cpr_dict)
 
             self._log.debug("Fetching VLRs for VNFR id = %s, cps = %s",
                             self._vnfr_id, self._vnfr.connection_point)
@@ -1767,7 +1899,7 @@ class VirtualNetworkFunctionRecord(object):
 
                 vlr_path = self.vlr_xpath(cp.vlr_ref)
                 self._log.debug("Fetching VLR with path = %s", vlr_path)
-                res_iter = yield from self._dts.query_read(self.vlr_xpath(cp.vlr_ref),
+                res_iter = yield from self._dts.query_read(vlr_path,
                                                            rwdts.XactFlag.MERGE)
                 for i in res_iter:
                     r = yield from i
@@ -1790,15 +1922,16 @@ class VirtualNetworkFunctionRecord(object):
         yield from self.publish_inventory(xact)
 
         # Publish inventory
-        self._log.debug("VNFR-ID %s: Creating VLs", self._vnfr_id)
+        self._log.debug("Create VLs {}: {}".format(self._vnfr_id, self._state))
         yield from self.create_vls()
 
         # publish the VNFR
-        self._log.debug("VNFR-ID %s: Publish VNFR", self._vnfr_id)
+        self._log.debug("Publish VNFR {}: {}".format(self._vnfr_id, self._state))
         yield from self.publish(xact)
 
+
         # instantiate VLs
-        self._log.debug("VNFR-ID %s: Instantiate VLs", self._vnfr_id)
+        self._log.debug("VNFR-ID %s: Instantiate VLs, restart mode %s", self._vnfr_id, restart_mode)
         try:
             yield from self.instantiate_vls(xact, restart_mode)
         except Exception as e:
@@ -1809,16 +1942,24 @@ class VirtualNetworkFunctionRecord(object):
         self.set_state(VirtualNetworkFunctionRecordState.VM_INIT_PHASE)
 
         # instantiate VDUs
-        self._log.debug("VNFR-ID %s: Create VDUs", self._vnfr_id)
+        self._log.debug("VNFR-ID %s: Create VDUs, restart mode %s", self._vnfr_id, restart_mode)
         yield from self.create_vdus(self, restart_mode)
 
+        try:
+            yield from self.vdu_cloud_init_instantiation()
+        except Exception as e:
+            self.set_state(VirtualNetworkFunctionRecordState.FAILED)
+            self._state_failed_reason = str(e)
+            yield from self.publish(xact)
+
         # publish the VNFR
-        self._log.debug("VNFR-ID %s: Publish VNFR", self._vnfr_id)
+        self._log.debug("VNFR {}: Publish VNFR with state {}".
+                        format(self._vnfr_id, self._state))
         yield from self.publish(xact)
 
         # instantiate VDUs
         # ToDo: Check if this should be prevented during restart
-        self._log.debug("VNFR-ID %s: Instantiate VDUs", self._vnfr_id)
+        self._log.debug("Instantiate VDUs {}: {}".format(self._vnfr_id, self._state))
         _ = self._loop.create_task(self.instantiate_vdus(xact, self))
 
         # publish the VNFR
@@ -1884,7 +2025,7 @@ class VirtualNetworkFunctionRecord(object):
 
 class VnfdDtsHandler(object):
     """ DTS handler for VNFD config changes """
-    XPATH = "C,/vnfd:vnfd-catalog/vnfd:vnfd"
+    XPATH = "C,/project-vnfd:vnfd-catalog/project-vnfd:vnfd"
 
     def __init__(self, dts, log, loop, vnfm):
         self._dts = dts
@@ -1898,6 +2039,14 @@ class VnfdDtsHandler(object):
         """ DTS registration handle """
         return self._regh
 
+    def deregister(self):
+        '''De-register from DTS'''
+        self._log.debug("De-register VNFD DTS handler for project {}".
+                        format(self._vnfm._project.name))
+        if self._regh:
+            self._regh.deregister()
+            self._regh = None
+
     @asyncio.coroutine
     def register(self):
         """ Register for VNFD configuration"""
@@ -1912,8 +2061,9 @@ class VnfdDtsHandler(object):
         @asyncio.coroutine
         def on_prepare(dts, acg, xact, xact_info, ks_path, msg, scratch):
             """ on prepare callback """
-            self._log.debug("Got on prepare for VNFD (path: %s) (action: %s)",
-                            ks_path.to_xpath(RwVnfmYang.get_schema()), msg)
+            self._log.debug("Got on prepare for VNFD (path: %s) (action: %s) (msg: %s)",
+                            ks_path.to_xpath(RwVnfmYang.get_schema()),
+                            xact_info.query_action, msg)
             fref = ProtobufC.FieldReference.alloc()
             fref.goto_whole_message(msg.to_pbcm())
 
@@ -1930,14 +2080,14 @@ class VnfdDtsHandler(object):
 
             xact_info.respond_xpath(rwdts.XactRspCode.ACK)
 
-        self._log.debug(
-            "Registering for VNFD config using xpath: %s",
-            VnfdDtsHandler.XPATH,
-            )
+        xpath = self._vnfm._project.add_project(VnfdDtsHandler.XPATH)
+        self._log.debug("Registering for VNFD config using xpath: {}".
+                        format(xpath))
+
         acg_hdl = rift.tasklets.AppConfGroup.Handler(on_apply=on_apply)
         with self._dts.appconf_group_create(handler=acg_hdl) as acg:
             self._regh = acg.register(
-                xpath=VnfdDtsHandler.XPATH,
+                xpath=xpath,
                 flags=rwdts.Flag.SUBSCRIBER | rwdts.Flag.DELTA_READY,
                 on_prepare=on_prepare)
 
@@ -1960,6 +2110,14 @@ class VcsComponentDtsHandler(object):
         """ DTS registration handle """
         return self._regh
 
+    def deregister(self):
+        '''De-register from DTS'''
+        self._log.debug("De-register VCS DTS handler for project {}".
+                        format(self._vnfm._project))
+        if self._regh:
+            self._regh.deregister()
+            self._regh = None
+
     @asyncio.coroutine
     def register(self):
         """ Registers VCS component dts publisher registration"""
@@ -1985,11 +2143,16 @@ class VcsComponentDtsHandler(object):
                         VcsComponentDtsHandler.XPATH, xact, path, msg)
 
 class VnfrConsoleOperdataDtsHandler(object):
-    """ registers 'D,/vnfr:vnfr-console/vnfr:vnfr[id]/vdur[id]' and handles CRUD from DTS"""
+    """
+    Registers 'D,/rw-project:project/vnfr:vnfr-console/vnfr:vnfr[id]/vdur[id]'
+    and handles CRUD from DTS
+    """
+
     @property
     def vnfr_vdu_console_xpath(self):
         """ path for resource-mgr"""
-        return ("D,/rw-vnfr:vnfr-console/rw-vnfr:vnfr[rw-vnfr:id='{}']/rw-vnfr:vdur[vnfr:id='{}']".format(self._vnfr_id,self._vdur_id))
+        return self._project.add_project("D,/rw-vnfr:vnfr-console/rw-vnfr:vnfr[rw-vnfr:id='{}']" +
+                                         "/rw-vnfr:vdur[vnfr:id='{}']".format(self._vnfr_id,self._vdur_id))
 
     def __init__(self, dts, log, loop, vnfm, vnfr_id, vdur_id, vdu_id):
         self._dts = dts
@@ -2002,6 +2165,16 @@ class VnfrConsoleOperdataDtsHandler(object):
         self._vdur_id = vdur_id
         self._vdu_id = vdu_id
 
+        self._project = vnfm._project
+
+    def deregister(self):
+        '''De-register from DTS'''
+        self._log.debug("De-register VNFR console DTS handler for project {}".
+                        format(self._project))
+        if self._regh:
+            self._regh.deregister()
+            self._regh = None
+
     @asyncio.coroutine
     def register(self):
         """ Register for VNFR VDU Operational Data read from dts """
@@ -2016,9 +2189,9 @@ class VnfrConsoleOperdataDtsHandler(object):
                 )
 
             if action == rwdts.QueryAction.READ:
-                schema = RwVnfrYang.YangData_RwVnfr_VnfrConsole_Vnfr_Vdur.schema()
+                schema = RwVnfrYang.YangData_RwProject_Project_VnfrConsole_Vnfr_Vdur.schema()
                 path_entry = schema.keyspec_to_entry(ks_path)
-                self._log.debug("VDU Opdata path is {}".format(path_entry))
+                self._log.debug("VDU Opdata path is {}".format(path_entry.key00.id))
                 try:
                     vnfr = self._vnfm.get_vnfr(self._vnfr_id)
                 except VnfRecordError as e:
@@ -2033,7 +2206,7 @@ class VnfrConsoleOperdataDtsHandler(object):
                         return
                     with self._dts.transaction() as new_xact:
                         resp = yield from vdur.read_resource(new_xact)
-                        vdur_console = RwVnfrYang.YangData_RwVnfr_VnfrConsole_Vnfr_Vdur()
+                        vdur_console = RwVnfrYang.YangData_RwProject_Project_VnfrConsole_Vnfr_Vdur()
                         vdur_console.id = self._vdur_id
                         if resp.console_url:
                             vdur_console.console_url = resp.console_url
@@ -2042,7 +2215,7 @@ class VnfrConsoleOperdataDtsHandler(object):
                         self._log.debug("Recevied console URL for vdu {} is {}".format(self._vdu_id,vdur_console))
                 except Exception:
                     self._log.exception("Caught exception while reading VDU %s", self._vdu_id)
-                    vdur_console = RwVnfrYang.YangData_RwVnfr_VnfrConsole_Vnfr_Vdur()
+                    vdur_console = RwVnfrYang.YangData_RwProject_Project_VnfrConsole_Vnfr_Vdur()
                     vdur_console.id = self._vdur_id
                     vdur_console.console_url = 'none'
 
@@ -2067,7 +2240,7 @@ class VnfrConsoleOperdataDtsHandler(object):
 
 
 class VnfrDtsHandler(object):
-    """ registers 'D,/vnfr:vnfr-catalog/vnfr:vnfr' and handles CRUD from DTS"""
+    """ registers 'D,/rw-project:project/vnfr:vnfr-catalog/vnfr:vnfr' and handles CRUD from DTS"""
     XPATH = "D,/vnfr:vnfr-catalog/vnfr:vnfr"
 
     def __init__(self, dts, log, loop, vnfm):
@@ -2077,6 +2250,7 @@ class VnfrDtsHandler(object):
         self._vnfm = vnfm
 
         self._regh = None
+        self._project = vnfm._project
 
     @property
     def regh(self):
@@ -2088,6 +2262,14 @@ class VnfrDtsHandler(object):
         """ Return VNF manager instance """
         return self._vnfm
 
+    def deregister(self):
+        '''De-register from DTS'''
+        self._log.debug("De-register VNFR DTS handler for project {}".
+                        format(self._project))
+        if self._regh:
+            self._regh.deregister()
+            self._regh = None
+
     @asyncio.coroutine
     def register(self):
         """ Register for vnfr create/update/delete/read requests from dts """
@@ -2149,7 +2331,7 @@ class VnfrDtsHandler(object):
                     vnfr.set_state(VirtualNetworkFunctionRecordState.FAILED)
                     yield from vnfr.publish(None)
             elif action == rwdts.QueryAction.DELETE:
-                schema = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.schema()
+                schema = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr.schema()
                 path_entry = schema.keyspec_to_entry(ks_path)
                 vnfr = self._vnfm.get_vnfr(path_entry.key00.id)
 
@@ -2168,7 +2350,7 @@ class VnfrDtsHandler(object):
                     self._log.error("Caught exception while deleting vnfr %s", path_entry.key00.id)
 
             elif action == rwdts.QueryAction.UPDATE:
-                schema = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.schema()
+                schema = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr.schema()
                 path_entry = schema.keyspec_to_entry(ks_path)
                 vnfr = None
                 try:
@@ -2196,14 +2378,15 @@ class VnfrDtsHandler(object):
 
             xact_info.respond_xpath(rwdts.XactRspCode.ACK)
 
-        self._log.debug("Registering for VNFR using xpath: %s",
-                        VnfrDtsHandler.XPATH,)
+        xpath = self._project.add_project(VnfrDtsHandler.XPATH)
+        self._log.debug("Registering for VNFR using xpath: {}".
+                        format(xpath))
 
         hdl = rift.tasklets.DTS.RegistrationHandler(on_commit=on_commit,
                                                     on_prepare=on_prepare,)
         handlers = rift.tasklets.Group.Handler(on_event=on_event,)
         with self._dts.group_create(handler=handlers) as group:
-            self._regh = group.register(xpath=VnfrDtsHandler.XPATH,
+            self._regh = group.register(xpath=xpath,
                                         handler=hdl,
                                         flags=(rwdts.Flag.PUBLISHER |
                                                rwdts.Flag.NO_PREP_READ |
@@ -2211,10 +2394,11 @@ class VnfrDtsHandler(object):
                                                rwdts.Flag.DATASTORE),)
 
     @asyncio.coroutine
-    def create(self, xact, path, msg):
+    def create(self, xact, xpath, msg):
         """
         Create a VNFR record in DTS with path and message
         """
+        path = self._project.add_project(xpath)
         self._log.debug("Creating VNFR xact = %s, %s:%s",
                         xact, path, msg)
 
@@ -2223,10 +2407,11 @@ class VnfrDtsHandler(object):
                         xact, path, msg)
 
     @asyncio.coroutine
-    def update(self, xact, path, msg):
+    def update(self, xact, xpath, msg):
         """
         Update a VNFR record in DTS with path and message
         """
+        path = self._project.add_project(xpath)
         self._log.debug("Updating VNFR xact = %s, %s:%s",
                         xact, path, msg)
         self.regh.update_element(path, msg)
@@ -2234,10 +2419,11 @@ class VnfrDtsHandler(object):
                         xact, path, msg)
 
     @asyncio.coroutine
-    def delete(self, xact, path):
+    def delete(self, xact, xpath):
         """
         Delete a VNFR record in DTS with path and message
         """
+        path = self._project.add_project(xpath)
         self._log.debug("Deleting VNFR xact = %s, %s", xact, path)
         self.regh.delete_element(path)
         self._log.debug("Deleted VNFR xact = %s, %s", xact, path)
@@ -2265,6 +2451,14 @@ class VnfdRefCountDtsHandler(object):
         """ Return the NS manager instance """
         return self._vnfm
 
+    def deregister(self):
+        '''De-register from DTS'''
+        self._log.debug("De-register VNFD Ref DTS handler for project {}".
+                        format(self._vnfm._project))
+        if self._regh:
+            self._regh.deregister()
+            self._regh = None
+
     @asyncio.coroutine
     def register(self):
         """ Register for VNFD ref count read from dts """
@@ -2279,7 +2473,7 @@ class VnfdRefCountDtsHandler(object):
                 )
 
             if action == rwdts.QueryAction.READ:
-                schema = RwVnfrYang.YangData_Vnfr_VnfrCatalog_VnfdRefCount.schema()
+                schema = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_VnfdRefCount.schema()
                 path_entry = schema.keyspec_to_entry(ks_path)
                 vnfd_list = yield from self._vnfm.get_vnfd_refcount(path_entry.key00.vnfd_id_ref)
                 for xpath, msg in vnfd_list:
@@ -2294,7 +2488,8 @@ class VnfdRefCountDtsHandler(object):
 
         hdl = rift.tasklets.DTS.RegistrationHandler(on_prepare=on_prepare,)
         with self._dts.group_create() as group:
-            self._regh = group.register(xpath=VnfdRefCountDtsHandler.XPATH,
+            self._regh = group.register(xpath=self._vnfm._project.add_project(
+                VnfdRefCountDtsHandler.XPATH),
                                         handler=hdl,
                                         flags=rwdts.Flag.PUBLISHER,
                                         )
@@ -2341,6 +2536,8 @@ class VdurDatastore(object):
 
         set_if_not_none('name', vdur._vdud.name)
         set_if_not_none('mgmt.ip', vdur.vm_management_ip)
+        # The below can be used for hostname
+        set_if_not_none('vdur_name', vdur.unique_short_name)
 
     def update(self, vdur):
         """Update the VDUR information in the datastore
@@ -2369,6 +2566,8 @@ class VdurDatastore(object):
 
         set_or_delete('name', vdur._vdud.name)
         set_or_delete('mgmt.ip', vdur.vm_management_ip)
+        # The below can be used for hostname
+        set_or_delete('vdur_name', vdur.unique_short_name)
 
     def remove(self, vdur_id):
         """Remove all of the data associated with specified VDUR
@@ -2422,16 +2621,18 @@ class VdurDatastore(object):
 
 class VnfManager(object):
     """ The virtual network function manager class """
-    def __init__(self, dts, log, loop, cluster_name):
+    def __init__(self, dts, log, loop, project, cluster_name):
         self._dts = dts
         self._log = log
         self._loop = loop
+        self._project = project
         self._cluster_name = cluster_name
 
         self._vcs_handler = VcsComponentDtsHandler(dts, log, loop, self)
         self._vnfr_handler = VnfrDtsHandler(dts, log, loop, self)
         self._vnfr_ref_handler = VnfdRefCountDtsHandler(dts, log, loop, self)
-        self._nsr_handler = mano_dts.NsInstanceConfigSubscriber(log, dts, loop, callback=self.handle_nsr)
+        self._nsr_handler = mano_dts.NsInstanceConfigSubscriber(
+            log, dts, loop, project, callback=self.handle_nsr)
 
         self._dts_handlers = [VnfdDtsHandler(dts, log, loop, self),
                               self._vnfr_handler,
@@ -2458,6 +2659,11 @@ class VnfManager(object):
         for hdl in self._dts_handlers:
             yield from hdl.register()
 
+    def deregister(self):
+        self._log.debug("De-register VNFM project {}".format(self._project.name))
+        for hdl in self._dts_handlers:
+            hdl.deregister()
+
     @asyncio.coroutine
     def run(self):
         """ Run this VNFM instance """
@@ -2543,11 +2749,13 @@ class VnfManager(object):
     @asyncio.coroutine
     def fetch_vnfd(self, vnfd_id):
         """ Fetch VNFDs based with the vnfd id"""
-        vnfd_path = VirtualNetworkFunctionRecord.vnfd_xpath(vnfd_id)
+        vnfd_path = self._project.add_project(
+            VirtualNetworkFunctionRecord.vnfd_xpath(vnfd_id))
         self._log.debug("Fetch vnfd with path %s", vnfd_path)
         vnfd = None
 
-        res_iter = yield from self._dts.query_read(vnfd_path, rwdts.XactFlag.MERGE)
+        res_iter = yield from self._dts.query_read(vnfd_path,
+                                                   rwdts.XactFlag.MERGE)
 
         for ent in res_iter:
             res = yield from ent
@@ -2606,8 +2814,8 @@ class VnfManager(object):
 
     def vnfd_refcount_xpath(self, vnfd_id):
         """ xpath for ref count entry """
-        return (VnfdRefCountDtsHandler.XPATH +
-                "[rw-vnfr:vnfd-id-ref = '{}']").format(vnfd_id)
+        return self._project.add_project(VnfdRefCountDtsHandler.XPATH +
+                                         "[rw-vnfr:vnfd-id-ref = '{}']").format(vnfd_id)
 
     @asyncio.coroutine
     def get_vnfd_refcount(self, vnfd_id):
@@ -2615,12 +2823,12 @@ class VnfManager(object):
         vnfd_list = []
         if vnfd_id is None or vnfd_id == "":
             for vnfd in self._vnfds_to_vnfr.keys():
-                vnfd_msg = RwVnfrYang.YangData_Vnfr_VnfrCatalog_VnfdRefCount()
+                vnfd_msg = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_VnfdRefCount()
                 vnfd_msg.vnfd_id_ref = vnfd
                 vnfd_msg.instance_ref_count = self._vnfds_to_vnfr[vnfd]
                 vnfd_list.append((self.vnfd_refcount_xpath(vnfd), vnfd_msg))
         elif vnfd_id in self._vnfds_to_vnfr:
-                vnfd_msg = RwVnfrYang.YangData_Vnfr_VnfrCatalog_VnfdRefCount()
+                vnfd_msg = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_VnfdRefCount()
                 vnfd_msg.vnfd_id_ref = vnfd_id
                 vnfd_msg.instance_ref_count = self._vnfds_to_vnfr[vnfd_id]
                 vnfd_list.append((self.vnfd_refcount_xpath(vnfd_id), vnfd_msg))
@@ -2628,6 +2836,31 @@ class VnfManager(object):
         return vnfd_list
 
 
+class VnfmProject(ManoProject):
+
+    def __init__(self, name, tasklet, **kw):
+        super(VnfmProject, self).__init__(tasklet.log, name)
+        self.update(tasklet)
+
+        self._vnfm = None
+
+    @asyncio.coroutine
+    def register (self):
+        try:
+            vm_parent_name = self._tasklet.tasklet_info.get_parent_vm_parent_instance_name()
+            assert vm_parent_name is not None
+            self._vnfm = VnfManager(self._dts, self.log, self.loop, self, vm_parent_name)
+            yield from self._vnfm.run()
+        except Exception:
+            print("Caught Exception in VNFM init:", sys.exc_info()[0])
+            raise
+
+    def deregister(self):
+        self._log.debug("De-register project {} for VnfmProject".
+                        format(self.name))
+        self._vnfm.deregister()
+
+
 class VnfmTasklet(rift.tasklets.Tasklet):
     """ VNF Manager tasklet class """
     def __init__(self, *args, **kwargs):
@@ -2636,7 +2869,12 @@ class VnfmTasklet(rift.tasklets.Tasklet):
         self.rwlog.set_subcategory("vnfm")
 
         self._dts = None
-        self._vnfm = None
+        self._project_handler = None
+        self.projects = {}
+
+    @property
+    def dts(self):
+        return self._dts
 
     def start(self):
         try:
@@ -2670,14 +2908,9 @@ class VnfmTasklet(rift.tasklets.Tasklet):
     @asyncio.coroutine
     def init(self):
         """ Task init callback """
-        try:
-            vm_parent_name = self.tasklet_info.get_parent_vm_parent_instance_name()
-            assert vm_parent_name is not None
-            self._vnfm = VnfManager(self._dts, self.log, self.loop, vm_parent_name)
-            yield from self._vnfm.run()
-        except Exception:
-            print("Caught Exception in VNFM init:", sys.exc_info()[0])
-            raise
+        self.log.debug("creating project handler")
+        self.project_handler = ProjectHandler(self, VnfmProject)
+        self.project_handler.register()
 
     @asyncio.coroutine
     def run(self):