X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=rwlaunchpad%2Fplugins%2Frwvnfm%2Frift%2Ftasklets%2Frwvnfmtasklet%2Frwvnfmtasklet.py;h=2cbe240429ad9e4a9afb72c9afd47a8b2fd81892;hb=ee71ccf6da85650a8fbd2019293535082f017b78;hp=d359aa4fbc9974983c77e568986aeab4a3c6abfd;hpb=d748ab1836d94ebe1273b1910954be3b2a2b4486;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 d359aa4f..2cbe2404 100755 --- a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py +++ b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py @@ -49,7 +49,9 @@ 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 +import rift.mano.utils.short_name as mano_short_name class VMResourceError(Exception): @@ -270,6 +272,7 @@ class VirtualDeploymentUnitRecord(object): loop, vdud, vnfr, + nsr_config, mgmt_intf, mgmt_network, cloud_account_name, @@ -281,6 +284,7 @@ class VirtualDeploymentUnitRecord(object): self._loop = loop 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 @@ -340,6 +344,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 +413,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 +452,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 +495,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 @@ -500,6 +552,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") @@ -552,18 +605,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 +664,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 +688,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 @@ -734,7 +822,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 +983,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 +1027,14 @@ 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, ivld_msg, vnfr_name, cloud_account_name, ip_profile=None): self._dts = dts self._log = log self._loop = loop 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 +1048,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): @@ -978,6 +1070,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,6 +1079,10 @@ 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) @@ -1369,6 +1466,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 +1488,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) @@ -1433,7 +1538,7 @@ 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: @@ -1441,10 +1546,7 @@ class VirtualNetworkFunctionRecord(object): #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: @@ -1463,6 +1565,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,16 +1593,22 @@ 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, @@ -1504,6 +1616,7 @@ class VirtualNetworkFunctionRecord(object): loop=self._loop, 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 +1640,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 +1669,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) @@ -1751,7 +1863,7 @@ 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) @@ -1797,8 +1909,9 @@ class VirtualNetworkFunctionRecord(object): self._log.debug("VNFR-ID %s: Publish VNFR", self._vnfr_id) 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,9 +1922,16 @@ 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) yield from self.publish(xact) @@ -2018,7 +2138,7 @@ class VnfrConsoleOperdataDtsHandler(object): if action == rwdts.QueryAction.READ: schema = RwVnfrYang.YangData_RwVnfr_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: @@ -2341,6 +2461,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 +2491,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