X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=rwlaunchpad%2Fplugins%2Frwvnfm%2Frift%2Ftasklets%2Frwvnfmtasklet%2Frwvnfmtasklet.py;h=253094f33ad8d8f2fef09806beea61c2d3dbd2e1;hb=a3bb91f092d378448cb870eccd45d43865de143c;hp=e493d3a0651033084b08bad5d2b0ffab8b00a98a;hpb=7203e6545b8957eef84f60845285b3256269637e;p=osm%2FSO.git diff --git a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py index e493d3a0..253094f3 100755 --- a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py +++ b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py @@ -51,6 +51,11 @@ 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): @@ -162,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 @@ -184,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) @@ -269,8 +275,10 @@ class VirtualDeploymentUnitRecord(object): dts, log, loop, + project, vdud, vnfr, + nsr_config, mgmt_intf, mgmt_network, cloud_account_name, @@ -280,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 @@ -298,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): @@ -341,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 """ @@ -392,14 +428,17 @@ class VirtualDeploymentUnitRecord(object): "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 @@ -425,24 +464,22 @@ class VirtualDeploymentUnitRecord(object): metadata_list = list() for metadata_item in opvolume.custom_meta_data: metadata_list.append(metadata_item.as_dict()) - if 'guest_params' not in vdurvol_data[0]: - vdurvol_data[0]['guest_params'] = dict() - vdurvol_data[0]['guest_params']['custom_meta_data'] = metadata_list - - if self._vm_resp.has_field('custom_boot_data'): - vdur_dict['custom_boot_data'] = dict() - if self._vm_resp.custom_boot_data.has_field('custom_drive'): - vdur_dict['custom_boot_data']['custom_drive'] = self._vm_resp.custom_boot_data.custom_drive - if self._vm_resp.custom_boot_data.has_field('custom_meta_data'): + 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.custom_boot_data.custom_meta_data: + for metadata_item in self._vm_resp.supplemental_boot_data.custom_meta_data: metadata_list.append(metadata_item.as_dict()) - vdur_dict['custom_boot_data']['custom_meta_data'] = metadata_list - if self._vm_resp.custom_boot_data.has_field('custom_config_files'): + 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.custom_boot_data.custom_config_files: + for file_item in self._vm_resp.supplemental_boot_data.config_file: file_list.append(file_item.as_dict()) - vdur_dict['custom_boot_data']['custom_config_files'] = file_list + vdur_dict['supplemental_boot_data']['config_file'] = file_list icp_list = [] ii_list = [] @@ -466,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 @@ -481,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): @@ -523,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") @@ -542,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] @@ -577,24 +620,24 @@ class VirtualDeploymentUnitRecord(object): def process_custom_bootdata(self, vm_create_msg_dict): """Process the custom boot data""" - if 'custom_config_files' not in vm_create_msg_dict['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) - script_extractor = rift.package.script.PackageScriptExtractor(self._log) - for custom_file_item in vm_create_msg_dict['custom_boot_data']['custom_config_files']: - if 'source' not in custom_file_item or 'dest' not in custom_file_item: + 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 = custom_file_item['source'] + source = file_item['source'] # Find source file in scripts dir of VNFD - self._vnfd_package_store.refresh() self._log.debug("Checking for source config file at %s", source) try: - source_file_str = script_extractor.read_script(stored_package, source) - except rift.package.script.ScriptExtractionError as e: + 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 - custom_file_item['source'] = source_file_str + file_item['source'] = source_file_str return @@ -605,13 +648,14 @@ class VirtualDeploymentUnitRecord(object): "hypervisor_epa", "host_epa", "volumes", - "custom_boot_data"] + "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: @@ -633,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): @@ -654,15 +701,22 @@ 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 'custom_boot_data' in vm_create_msg_dict: + if 'supplemental_boot_data' in vm_create_msg_dict: self.process_custom_bootdata(vm_create_msg_dict) msg = RwResourceMgrYang.VDUEventData() @@ -693,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 @@ -781,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) @@ -942,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": @@ -986,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 @@ -1006,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): @@ -1015,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 """ @@ -1025,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} @@ -1033,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 @@ -1132,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 @@ -1184,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): @@ -1265,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: @@ -1315,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: @@ -1335,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 @@ -1357,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()) @@ -1372,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) @@ -1402,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 @@ -1416,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 """ @@ -1431,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) @@ -1469,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')} @@ -1480,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, @@ -1510,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 """ @@ -1534,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, @@ -1574,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 @@ -1603,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) @@ -1696,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): @@ -1787,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) @@ -1798,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) @@ -1814,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 @@ -1837,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: @@ -1856,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 @@ -1931,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 @@ -1945,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""" @@ -1959,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()) @@ -1977,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) @@ -2007,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""" @@ -2032,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 @@ -2049,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 """ @@ -2063,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: @@ -2080,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 @@ -2089,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' @@ -2114,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): @@ -2124,6 +2250,7 @@ class VnfrDtsHandler(object): self._vnfm = vnfm self._regh = None + self._project = vnfm._project @property def regh(self): @@ -2135,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 """ @@ -2196,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) @@ -2215,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: @@ -2243,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 | @@ -2258,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) @@ -2270,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) @@ -2281,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) @@ -2312,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 """ @@ -2326,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: @@ -2341,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, ) @@ -2388,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 @@ -2416,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 @@ -2469,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, @@ -2505,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 """ @@ -2590,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 @@ -2653,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): @@ -2662,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)) @@ -2675,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): @@ -2683,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: @@ -2717,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):