def create_mea(self, context, mea): mea_info = mea['mea'] name = mea_info['name'] # if mead_template specified, create mead from template # create template dictionary structure same as needed in create_mead() if mea_info.get('mead_template'): mead_name = utils.generate_resource_name(name, 'inline') mead = { 'mead': { 'attributes': { 'mead': mea_info['mead_template'] }, 'name': mead_name, 'template_source': 'inline', 'service_types': [{ 'service_type': 'mead' }] } } mea_info['mead_id'] = self.create_mead(context, mead).get('id') mea_attributes = mea_info['attributes'] if mea_attributes.get('param_values'): param = mea_attributes['param_values'] if isinstance(param, dict): # TODO(sripriya) remove this yaml dump once db supports storing # json format of yaml files in a separate column instead of # key value string pairs in mea attributes table mea_attributes['param_values'] = yaml.safe_dump(param) else: self._report_deprecated_yaml_str() if mea_attributes.get('config'): config = mea_attributes['config'] if isinstance(config, dict): # TODO(sripriya) remove this yaml dump once db supports storing # json format of yaml files in a separate column instead of # key value string pairs in mea attributes table mea_attributes['config'] = yaml.safe_dump(config) else: self._report_deprecated_yaml_str() infra_driver, vim_auth = self._get_infra_driver(context, mea_info) if infra_driver not in self._mea_manager: LOG.debug( 'unknown vim driver ' '%(infra_driver)s in %(drivers)s', { 'infra_driver': infra_driver, 'drivers': cfg.CONF.apmec.infra_driver }) raise mem.InvalidInfraDriver(vim_name=infra_driver) mea_dict = self._create_mea(context, mea_info, vim_auth, infra_driver) def create_mea_wait(): self._create_mea_wait(context, mea_dict, vim_auth, infra_driver) if mea_dict['status'] is not constants.ERROR: self.add_mea_to_monitor(context, mea_dict) self.config_mea(context, mea_dict) self.spawn_n(create_mea_wait) return mea_dict
def update_meca(self, context, meca_id, meca): meca_info = meca['meca'] meca_old = super(MeoPlugin, self).get_meca(context, meca_id) name = meca_old['name'] # create inline meafgd if given by user if meca_info.get('mecad_template'): meca_name = utils.generate_resource_name(name, 'inline') mecad = {'mecad': {'tenant_id': meca_old['tenant_id'], 'name': meca_name, 'attributes': { 'mecad': meca_info['mecad_template']}, 'template_source': 'inline', 'description': meca_old['description']}} try: meca_info['mecad_id'] = \ self.create_mecad(context, mecad).get('id') except Exception: with excutils.save_and_reraise_exception(): super(MeoPlugin, self)._update_meca_status( context, meca_id, constants.ACTIVE) mecad = self.get_mecad(context, meca_info['mecad_id']) mecad_dict = yaml.safe_load(mecad['attributes']['mecad']) mem_plugin = manager.ApmecManager.get_service_plugins()['MEM'] onboarded_meads = mem_plugin.get_meads(context, []) region_name = meca.setdefault('placement_attr', {}).get( 'region_name', None) vim_res = self.vim_client.get_vim(context, meca_old['vim_id'], region_name) driver_type = vim_res['vim_type'] # Step-1 param_values = dict() if 'get_input' in str(mecad_dict): self._process_parameterized_input(meca['meca']['attributes'], mecad_dict) # Step-2 meads = mecad['meads'] # mead_dict is used while generating workflow mead_dict = dict() for node_name, node_val in \ (mecad_dict['topology_template']['node_templates']).items(): if node_val.get('type') not in meads.keys(): continue mead_name = meads[node_val.get('type')] if not mead_dict.get(mead_name): mead_dict[mead_name] = { 'id': self._get_mead_id(mead_name, onboarded_meads), 'instances': [node_name] } else: mead_dict[mead_name]['instances'].append(node_name) if not node_val.get('requirements'): continue if not param_values.get(mead_name): param_values[mead_name] = {} param_values[mead_name]['substitution_mappings'] = dict() req_dict = dict() requirements = node_val.get('requirements') for requirement in requirements: req_name = list(requirement.keys())[0] req_val = list(requirement.values())[0] res_name = req_val + meca['meca']['mecad_id'][:11] req_dict[req_name] = res_name if req_val in mecad_dict['topology_template']['node_templates']: # noqa param_values[mead_name]['substitution_mappings'][ res_name] = mecad_dict['topology_template'][ 'node_templates'][req_val] param_values[mead_name]['substitution_mappings'][ 'requirements'] = req_dict meca['mead_details'] = mead_dict # Step-3 kwargs = {'meca': meca, 'params': param_values} # NOTE NoTasksException is raised if no tasks. workflow = self._vim_drivers.invoke( driver_type, 'prepare_and_create_workflow', resource='mea', action='create', auth_dict=self.get_auth_dict(context), kwargs=kwargs) try: mistral_execution = self._vim_drivers.invoke( driver_type, 'execute_workflow', workflow=workflow, auth_dict=self.get_auth_dict(context)) except Exception as ex: LOG.error('Error while executing workflow: %s', ex) self._vim_drivers.invoke(driver_type, 'delete_workflow', workflow_id=workflow['id'], auth_dict=self.get_auth_dict(context)) raise ex meca_dict = super(MeoPlugin, self)._update_meca_pre(context, meca_id) def _update_meca_wait(self_obj, meca_id, execution_id): exec_state = "RUNNING" mistral_retries = MISTRAL_RETRIES while exec_state == "RUNNING" and mistral_retries > 0: time.sleep(MISTRAL_RETRY_WAIT) exec_state = self._vim_drivers.invoke( driver_type, 'get_execution', execution_id=execution_id, auth_dict=self.get_auth_dict(context)).state LOG.debug('status: %s', exec_state) if exec_state == 'SUCCESS' or exec_state == 'ERROR': break mistral_retries = mistral_retries - 1 error_reason = None if mistral_retries == 0 and exec_state == 'RUNNING': error_reason = _( "MECA update is not completed within" " {wait} seconds as creation of mistral" " execution {mistral} is not completed").format( wait=MISTRAL_RETRIES * MISTRAL_RETRY_WAIT, mistral=execution_id) exec_obj = self._vim_drivers.invoke( driver_type, 'get_execution', execution_id=execution_id, auth_dict=self.get_auth_dict(context)) self._vim_drivers.invoke(driver_type, 'delete_execution', execution_id=execution_id, auth_dict=self.get_auth_dict(context)) self._vim_drivers.invoke(driver_type, 'delete_workflow', workflow_id=workflow['id'], auth_dict=self.get_auth_dict(context)) super(MeoPlugin, self)._update_meca_post( context, meca_id, exec_obj, mead_dict, error_reason) self.spawn_n(_update_meca_wait, self, meca_dict['id'], mistral_execution.id) return meca_dict
def create_mes(self, context, mes): """Create MES and corresponding MEAs. :param mes: mes dict which contains mesd_id and attributes This method has 3 steps: step-1: substitute all get_input params to its corresponding values step-2: Build params dict for substitution mappings case through which MEAs will actually substitute their requirements. step-3: Create mistral workflow and execute the workflow """ mes_info = mes['mes'] name = mes_info['name'] if mes_info.get('mesd_template'): mesd_name = utils.generate_resource_name(name, 'inline') mesd = { 'mesd': { 'attributes': { 'mesd': mes_info['mesd_template'] }, 'description': mes_info['description'], 'name': mesd_name, 'template_source': 'inline', 'tenant_id': mes_info['tenant_id'] } } mes_info['mesd_id'] = self.create_mesd(context, mesd).get('id') mesd = self.get_mesd(context, mes['mes']['mesd_id']) mesd_dict = yaml.safe_load(mesd['attributes']['mesd']) mem_plugin = manager.ApmecManager.get_service_plugins()['MEM'] onboarded_meads = mem_plugin.get_meads(context, []) region_name = mes.setdefault('placement_attr', {}).get('region_name', None) vim_res = self.vim_client.get_vim(context, mes['mes']['vim_id'], region_name) driver_type = vim_res['vim_type'] if not mes['mes']['vim_id']: mes['mes']['vim_id'] = vim_res['vim_id'] nsds = mesd['attributes'].get('nsds') if nsds: for nsd in nsds: vim_obj = self.get_vim(context, mes['mes']['vim_id'], mask_password=False) self._build_vim_auth(context, vim_obj) client = tackerclient(vim_obj['auth_cred']) ns_name = nsd + name nsd_instance = client.nsd_get(nsd) ns_arg = {'ns': {'nsd_id': nsd_instance, 'name': ns_name}} ns_instance = client.ns_create(ns_arg) vnffgds = mesd['attributes'].get('vnffgds') if vnffgds: for vnffgd in vnffgds: vim_obj = self.get_vim(context, mes['mes']['vim_id'], mask_password=False) self._build_vim_auth(context, vim_obj) client = tackerclient(vim_obj['auth_cred']) vnffgd_name = vnffgd + name vnffgd_instance = client.vnffgd_get(vnffgd) vnffg_arg = { 'vnffg': { 'vnffgd_id': vnffgd_instance, 'name': vnffgd_name } } time.sleep(300) vnffg_instance = client.vnffg_create(vnffg_arg) # Step-1 param_values = mes['mes']['attributes'].get('param_values', {}) if 'get_input' in str(mesd_dict): self._process_parameterized_input(mes['mes']['attributes'], mesd_dict) # Step-2 meads = mesd['meads'] # mead_dict is used while generating workflow mead_dict = dict() for node_name, node_val in \ (mesd_dict['topology_template']['node_templates']).items(): if node_val.get('type') not in meads.keys(): continue mead_name = meads[node_val.get('type')] if not mead_dict.get(mead_name): mead_dict[mead_name] = { 'id': self._get_mead_id(mead_name, onboarded_meads), 'instances': [node_name] } else: mead_dict[mead_name]['instances'].append(node_name) if not node_val.get('requirements'): continue if not param_values.get(mead_name): param_values[mead_name] = {} param_values[mead_name]['substitution_mappings'] = dict() req_dict = dict() requirements = node_val.get('requirements') for requirement in requirements: req_name = list(requirement.keys())[0] req_val = list(requirement.values())[0] res_name = req_val + mes['mes']['mesd_id'][:11] req_dict[req_name] = res_name if req_val in mesd_dict['topology_template']['node_templates']: param_values[mead_name]['substitution_mappings'][ res_name] = mesd_dict['topology_template'][ 'node_templates'][req_val] param_values[mead_name]['substitution_mappings'][ 'requirements'] = req_dict mes['mead_details'] = mead_dict # Step-3 kwargs = {'mes': mes, 'params': param_values} # NOTE NoTasksException is raised if no tasks. workflow = self._vim_drivers.invoke( driver_type, 'prepare_and_create_workflow', resource='mea', action='create', auth_dict=self.get_auth_dict(context), kwargs=kwargs) try: mistral_execution = self._vim_drivers.invoke( driver_type, 'execute_workflow', workflow=workflow, auth_dict=self.get_auth_dict(context)) except Exception as ex: LOG.error('Error while executing workflow: %s', ex) self._vim_drivers.invoke(driver_type, 'delete_workflow', workflow_id=workflow['id'], auth_dict=self.get_auth_dict(context)) raise ex mes_dict = super(MeoPlugin, self).create_mes(context, mes) def _create_mes_wait(self_obj, mes_id, execution_id): exec_state = "RUNNING" mistral_retries = MISTRAL_RETRIES while exec_state == "RUNNING" and mistral_retries > 0: time.sleep(MISTRAL_RETRY_WAIT) exec_state = self._vim_drivers.invoke( driver_type, 'get_execution', execution_id=execution_id, auth_dict=self.get_auth_dict(context)).state LOG.debug('status: %s', exec_state) if exec_state == 'SUCCESS' or exec_state == 'ERROR': break mistral_retries = mistral_retries - 1 error_reason = None if mistral_retries == 0 and exec_state == 'RUNNING': error_reason = _( "MES creation is not completed within" " {wait} seconds as creation of mistral" " execution {mistral} is not completed").format( wait=MISTRAL_RETRIES * MISTRAL_RETRY_WAIT, mistral=execution_id) exec_obj = self._vim_drivers.invoke( driver_type, 'get_execution', execution_id=execution_id, auth_dict=self.get_auth_dict(context)) self._vim_drivers.invoke(driver_type, 'delete_execution', execution_id=execution_id, auth_dict=self.get_auth_dict(context)) self._vim_drivers.invoke(driver_type, 'delete_workflow', workflow_id=workflow['id'], auth_dict=self.get_auth_dict(context)) super(MeoPlugin, self).create_mes_post(context, mes_id, exec_obj, mead_dict, error_reason) self.spawn_n(_create_mes_wait, self, mes_dict['id'], mistral_execution.id) return mes_dict
def update_mes(self, context, mes_id, mes): args = dict() mes_info = mes['mes'] old_mes = super(MesoPlugin, self).get_mes(context, mes_id) name = old_mes['name'] lftover = dict() # vm_capacity = 3 # create inline mesd if given by user def _update_nsd_template(req_mesd_dict): build_nsd_dict = dict() if req_mesd_dict['imports'].get('nsds'): args['NS'] = dict() # Todo: Support multiple NSs # For framework evaluation nsd_templates = req_mesd_dict['imports']['nsds']['nsd_templates'] # noqa if isinstance(nsd_templates, dict): if nsd_templates.get('requirements'): old_reused = old_mes['reused'] vnf_mapping_list = nsd_templates['requirements'] for vnf_mapping_dict in vnf_mapping_list: for old_vnf_name, old_nfins_list in old_reused.items(): # noqa if vnf_mapping_dict['name'] == old_vnf_name: len_diff = len([lend for lend in old_nfins_list if lend > 0]) # noqa diff = len_diff - vnf_mapping_dict['nf_ins'] # noqa if diff < 0: lftover.update({old_vnf_name: -diff}) vm_capacity = VM_CAPA[old_vnf_name] old_reused[old_vnf_name].extend([vm_capacity] * (-diff)) # noqa # old_reused[old_vnf_name] = diff temp = vnf_mapping_dict['nf_ins'] for index, nfins in enumerate(old_nfins_list): # noqa if nfins > 0: old_nfins_list[index] = old_nfins_list[index] - 1 # noqa temp = temp - 1 if temp == 0: break formal_req = list() for nf_name, nf_ins in lftover.items(): vnfd_name = 'vnfd' + nf_name[3] + str(nf_ins) formal_req.append(vnfd_name) if formal_req: build_nsd_dict['tosca_definitions_version'] = 'tosca_simple_profile_for_nfv_1_0_0' # noqa build_nsd_dict['description'] = old_mes['description'] build_nsd_dict['imports'] = formal_req build_nsd_dict['topology_template'] = dict() build_nsd_dict['topology_template']['node_templates'] = dict() # noqa for nf_name, nf_ins in lftover.items(): node = 'tosca.nodes.nfv.' + nf_name node_dict = dict() node_dict['type'] = node build_nsd_dict['topology_template']['node_templates'].update({nf_name: node_dict}) # noqa return build_nsd_dict if mes_info.get('mesd_template'): # Build vnf_dict here mes_name = utils.generate_resource_name(name, 'inline') mesd = {'mesd': {'tenant_id': old_mes['tenant_id'], 'name': mes_name, 'attributes': { 'mesd': mes_info['mesd_template']}, 'template_source': 'inline', 'description': old_mes['description']}} try: mes_info['mesd_id'] = \ self.create_mesd(context, mesd).get('id') except Exception: with excutils.save_and_reraise_exception(): super(MesoPlugin, self)._update_mes_status(context, mes_id, constants.ACTIVE) # noqa mesd = self.get_mesd(context, mes_info['mesd_id']) mesd_dict = yaml.safe_load(mesd['attributes']['mesd']) new_mesd_mapping = mesd['mesd_mapping'] region_name = mes.setdefault('placement_attr', {}).get( 'region_name', None) vim_res = self.vim_client.get_vim(context, old_mes['vim_id'], region_name) if mesd_dict['imports'].get('meads'): # Update MECA meo_plugin = manager.ApmecManager.get_service_plugins()['MEO'] # Build the MECA template here mead_tpl_dict = dict() mead_tpl_dict['imports'] =\ mesd_dict['imports']['meads']['mead_templates'] mecad_dict = copy.deepcopy(mesd_dict) mecad_dict.pop('imports') mecad_dict.update(mead_tpl_dict) mecad_arg = {'meca': {'mecad_template': mecad_dict}} old_meca_id = old_mes['mes_mapping']['MECA'] meca_id = meo_plugin.update_meca(context, old_meca_id, mecad_arg) # noqa if mesd_dict['imports'].get('nsds'): nfv_driver = None nfv_driver = mesd_dict['imports']['nsds'].get('nfv_driver') if not nfv_driver: raise meso.NFVDriverNotFound(mesd_name=mesd_dict['name']) nfv_driver = nfv_driver.lower() req_mesd_dict = yaml.safe_load(mes_info['mesd_template']) new_nsd_template = _update_nsd_template(req_mesd_dict) nsd_template = None if isinstance(new_mesd_mapping.get('NSD'), list): nsd_name = new_mesd_mapping['NSD'][0] nsd_dict = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'nsd_get_by_name', nsd_name=nsd_name, auth_attr=vim_res['vim_auth'], ) nsd_template = yaml.safe_load(nsd_dict['attributes']['nsd']) actual_nsd_template = new_nsd_template if new_nsd_template else nsd_template # noqa if actual_nsd_template: old_ns_id = old_mes['mes_mapping']['NS'][0] ns_arg = {'ns': {'nsd_template': actual_nsd_template}} self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_update', ns_id=old_ns_id, ns_dict=ns_arg, auth_attr=vim_res['vim_auth'], ) if mesd_dict['imports'].get('vnffgds'): # Todo: Support multiple VNFFGs nfv_driver = None nfv_driver = mesd_dict['imports']['nsds'].get('nfv_driver') if not nfv_driver: raise meso.NFVDriverNotFound(mesd_name=mesd_dict['name']) nfv_driver = nfv_driver.lower() vnffgd_name = new_mesd_mapping['VNFFGD'][0] vnffgd_dict = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'vnffgd_get_by_name', vnffgd_name=vnffgd_name, auth_attr=vim_res['vim_auth'], ) vnffgd_template = yaml.safe_load( vnffgd_dict['attributes']['vnffgd']) old_vnffg_id = old_mes['mes_mapping']['VNFFG'][0] vnffg_arg = {'vnffg': {'vnffgd_template': vnffgd_template}} self._nfv_drivers.invoke( nfv_driver, 'vnffg_update', vnffg_id=old_vnffg_id, vnffg_dict=vnffg_arg, auth_attr=vim_res['vim_auth'], ) mes_dict = super(MesoPlugin, self)._update_mes_pre(context, mes_id) def _update_mes_wait(self_obj, mes_id): args = dict() mes_status = "ACTIVE" ns_status = "PENDING_UPDATE" vnffg_status = "PENDING_UPDATE" mec_status = "PENDING_UPDATE" ns_retries = NS_RETRIES mec_retries = MEC_RETRIES vnffg_retries = VNFFG_RETRIES error_reason_meca = None error_reason_ns = None error_reason_vnffg = None # Check MECA if mesd_dict['imports'].get('meads'): while mec_status == "PENDING_UPDATE" and mec_retries > 0: time.sleep(MEC_RETRY_WAIT) meca_id = old_mes['mes_mapping']['MECA'] meca_list = meo_plugin.get_mecas(context) is_deleted = True for meca in meca_list: if meca_id in meca['id']: is_deleted = False if is_deleted: break mec_status = meo_plugin.get_meca(context, meca_id)['status'] # noqa LOG.debug('status: %s', mec_status) if mec_status == 'ERROR': break mec_retries = mec_retries - 1 if mec_retries == 0 and mec_status == 'PENDING_UPDATE': error_reason_meca = _( "MES update is not completed within" " {wait} seconds as update of MECA").format( wait=MEC_RETRIES * MEC_RETRY_WAIT) # Check NS/VNFFG status if mesd_dict['imports'].get('nsds'): while ns_status == "PENDING_UPDATE" and ns_retries > 0: time.sleep(NS_RETRY_WAIT) ns_list = old_mes['mes_mapping']['NS'] # Todo: support multiple NSs is_existed = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_check', ns_id=ns_list[0], auth_attr=vim_res['vim_auth'], ) if not is_existed: break ns_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_get', ns_id=ns_list[0], auth_attr=vim_res['vim_auth'], ) ns_status = ns_instance['status'] LOG.debug('status: %s', ns_status) if ns_status == 'ERROR': break ns_retries = ns_retries - 1 if ns_retries == 0 and ns_status == 'PENDING_UPDATE': error_reason_ns = _( "MES update is not completed within" " {wait} seconds as update of NS(s)").format( wait=NS_RETRIES * NS_RETRY_WAIT) if mesd_dict['imports'].get('vnffgds'): while vnffg_status == "PENDING_UPDATE" and vnffg_retries > 0: time.sleep(VNFFG_RETRY_WAIT) vnffg_list = old_mes['mes_mapping']['VNFFG'] # Todo: support multiple VNFFGs is_existed = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'vnffg_check', vnffg_id=vnffg_list[0], auth_attr=vim_res['vim_auth'], ) if not is_existed: break vnffg_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'vnffg_get', vnffg_id=vnffg_list[0], auth_attr=vim_res['vim_auth'], ) vnffg_status = vnffg_instance['status'] LOG.debug('status: %s', vnffg_status) if vnffg_status == 'ERROR': break vnffg_retries = vnffg_retries - 1 if vnffg_retries == 0 and vnffg_status == 'PENDING_UPDATE': error_reason_vnffg = _( "MES update is not completed within" " {wait} seconds as update of VNFFG(s)").format( wait=VNFFG_RETRIES * VNFFG_RETRY_WAIT) args['NS'] = old_mes['reused'] if mec_status == "ERROR" or ns_status == "ERROR" or vnffg_status == "ERROR": # noqa mes_status = "ERROR" error_reason = None for reason in [error_reason_meca, error_reason_ns, error_reason_vnffg]: # noqa if reason: error_reason = reason mes_status = "PENDING_UPDATE" super(MesoPlugin, self)._update_mes_post(context, mes_id, error_reason, mes_status, args) # noqa self.spawn_n(_update_mes_wait, self, mes_dict['id']) return mes_dict
def create_mes(self, context, mes): """Create MES and corresponding MEAs. :param mes: mes dict which contains mesd_id and attributes This method has 2 steps: step-1: Call MEO API to create MEAs step-2: Call Tacker drivers to create NSs """ mes_info = mes['mes'] name = mes_info['name'] mes_info['mes_mapping'] = dict() if mes_info.get('mesd_template'): mesd_name = utils.generate_resource_name(name, 'inline') mesd = {'mesd': { 'attributes': {'mesd': mes_info['mesd_template']}, 'description': mes_info['description'], 'name': mesd_name, 'template_source': 'inline', 'tenant_id': mes_info['tenant_id']}} mes_info['mesd_id'] = self.create_mesd(context, mesd).get('id') mesd = self.get_mesd(context, mes['mes']['mesd_id']) mesd_dict = yaml.safe_load(mesd['attributes']['mesd']) meo_plugin = manager.ApmecManager.get_service_plugins()['MEO'] region_name = mes.setdefault('placement_attr', {}).get( 'region_name', None) vim_res = self.vim_client.get_vim(context, mes['mes']['vim_id'], region_name) # driver_type = vim_res['vim_type'] if not mes['mes']['vim_id']: mes['mes']['vim_id'] = vim_res['vim_id'] ########################################## # Detect MANO driver here: # Defined in the Tosca template nfv_driver = None if mesd_dict['imports'].get('nsds'): nfv_driver = mesd_dict['imports']['nsds']['nfv_driver'] nfv_driver = nfv_driver.lower() if mesd_dict['imports'].get('vnffgds'): nfv_driver = mesd_dict['imports']['vnffgds']['nfv_driver'] nfv_driver = nfv_driver.lower() ########################################## def _find_vnf_ins(cd_mes): al_ns_id_list = cd_mes['mes_mapping'].get('NS') if not al_ns_id_list: return None, None al_ns_id = al_ns_id_list[0] try: ns_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_get', ns_id=al_ns_id, auth_attr=vim_res['vim_auth'], ) except Exception: return None, None if ns_instance['status'] != 'ACTIVE': return None, None al_vnf = ns_instance['vnf_ids'] al_vnf_dict = ast.literal_eval(al_vnf) return ns_instance['id'], al_vnf_dict def _run_meso_algorithm(req_vnf_list): is_accepted = False al_mes_list = self.get_mess(context) ns_candidate = dict() for al_mes in al_mes_list: ns_candidate[al_mes['id']] = dict() if al_mes['status'] != "ACTIVE": continue al_ns_id, al_vnf_dict = _find_vnf_ins(al_mes) if not al_ns_id: continue ns_candidate[al_mes['id']][al_ns_id] = dict() for req_vnf_dict in req_vnf_list: for vnf_name, al_vnf_id in al_vnf_dict.items(): if req_vnf_dict['name'] == vnf_name: # Todo: remember to change this with VM capacity len_diff =\ len([lend for lend in al_mes['reused'][vnf_name] if lend > 0]) avail = len_diff - req_vnf_dict['nf_ins'] ns_candidate[al_mes['id']][al_ns_id].\ update({vnf_name: avail}) ns_cds = dict() deep_ns = dict() for mesid, ns_data_dict in ns_candidate.items(): for nsid, resev_dict in ns_data_dict.items(): if len(resev_dict) == len(req_vnf_list): nf_ins_list =\ [nf_ins for nf_name, nf_ins in resev_dict.items() if nf_ins >= 0] if len(nf_ins_list) == len(req_vnf_list): total_ins = sum(nf_ins_list) ns_cds[mesid] = total_ins else: extra_nf_ins_list =\ [-nf_ins for nf_name, nf_ins in resev_dict.items() if nf_ins < 0] total_ins = sum(extra_nf_ins_list) deep_ns[mesid] = total_ins if ns_cds: selected_mes1 = min(ns_cds, key=ns_cds.get) is_accepted = True return is_accepted, selected_mes1, None if deep_ns: selected_mes2 = min(deep_ns, key=deep_ns.get) is_accepted = True return is_accepted, selected_mes2, ns_candidate[selected_mes2] return is_accepted, None, None build_nsd_dict = dict() if mesd_dict['imports'].get('nsds'): # For framework evaluation nsd_template = mesd_dict['imports']['nsds']['nsd_templates'] if isinstance(nsd_template, dict): if nsd_template.get('requirements'): req_nf_dict = nsd_template['requirements'] req_nf_list = list() for vnf_dict in req_nf_dict: # Todo: make the requests more natural req_nf_list.append( {'name': vnf_dict['name'], 'nf_ins': int(vnf_dict['vnfd_template'][5])}) is_accepted, cd_mes_id, cd_vnf_dict =\ _run_meso_algorithm(req_nf_list) if is_accepted: new_mesd_dict = dict() ref_mesd_dict = copy.deepcopy(mesd_dict) ref_mesd_dict['imports']['nsds']['nsd_templates']['requirements'] = \ req_nf_list new_mesd_dict['mes'] = dict() new_mesd_dict['mes'] =\ {'mesd_template': yaml.safe_dump(ref_mesd_dict)} self.update_mes(context, cd_mes_id, new_mesd_dict) return cd_mes_id else: # Create the inline NS with the following template import_list = list() node_dict = dict() for vnfd in req_nf_dict: import_list.append(vnfd['vnfd_template']) node = 'tosca.nodes.nfv.' + vnfd['name'] node_dict[vnfd['name']] = {'type': node} build_nsd_dict['tosca_definitions_version'] =\ 'tosca_simple_profile_for_nfv_1_0_0' build_nsd_dict['description'] = mes_info['description'] build_nsd_dict['imports'] = import_list build_nsd_dict['topology_template'] = dict() build_nsd_dict['topology_template']['node_templates'] =\ node_dict nsds = mesd['attributes'].get('nsds') mes_info['mes_mapping']['NS'] = list() if nsds: nsds_list = nsds.split('-') for nsd in nsds_list: ns_name = nsd + '-' + name + '-' + uuidutils.generate_uuid() # noqa nsd_instance = self._nfv_drivers.invoke( nfv_driver, 'nsd_get_by_name', nsd_name=nsd, auth_attr=vim_res['vim_auth'],) if nsd_instance: ns_arg = {'ns': {'nsd_id': nsd_instance['id'], 'name': ns_name}} ns_id = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_create', ns_dict=ns_arg, auth_attr=vim_res['vim_auth'], ) mes_info['mes_mapping']['NS'].append(ns_id) if build_nsd_dict: ns_name = 'nsd' + name + '-' + uuidutils.generate_uuid() ns_arg = {'ns': {'nsd_template': build_nsd_dict, 'name': ns_name, 'description': mes_info['description'], 'vim_id': '', 'tenant_id': mes_info['tenant_id'], 'attributes': {}}} ns_id = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_create', ns_dict=ns_arg, auth_attr=vim_res['vim_auth'], ) mes_info['mes_mapping']['NS'].append(ns_id) vnffgds = mesd['attributes'].get('vnffgds') if mesd_dict['imports'].get('vnffgds'): vnffgds_list = vnffgds.split('-') mes_info['mes_mapping']['VNFFG'] = list() for vnffgd in vnffgds_list: vnffg_name = vnffgds + '-' + name + '-' + uuidutils.generate_uuid() # noqa vnffgd_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'vnffgd_get_by_name', vnffgd_name=vnffgd, auth_attr=vim_res['vim_auth'], ) if vnffgd_instance: vnffg_arg = {'vnffg': {'vnffgd_id': vnffgd_instance['id'], 'name': vnffg_name}} # noqa vnffg_id = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'vnffg_create', vnffg_dict=vnffg_arg, auth_attr=vim_res['vim_auth'], ) mes_info['mes_mapping']['VNFFG'].append(vnffg_id) # meca_id = dict() # Create MEAs using MEO APIs try: meca_name = 'meca' + '-' + name + '-' + uuidutils.generate_uuid() # Separate the imports out from template mead_tpl_dict = dict() mead_tpl_dict['imports'] =\ mesd_dict['imports']['meads']['mead_templates'] mecad_dict = copy.deepcopy(mesd_dict) mecad_dict.pop('imports') mecad_dict.update(mead_tpl_dict) LOG.debug('mesd %s', mecad_dict) meca_arg = {'meca': {'mecad_template': mecad_dict, 'name': meca_name, # noqa 'description': mes_info['description'], 'tenant_id': mes_info['tenant_id'], 'vim_id': mes_info['vim_id'], 'attributes': {}}} meca_dict = meo_plugin.create_meca(context, meca_arg) mes_info['mes_mapping']['MECA'] = meca_dict['id'] except Exception as e: LOG.error('Error while creating the MECAs: %s', e) # Call Tacker client driver mes_dict = super(MesoPlugin, self).create_mes(context, mes) def _create_mes_wait(self_obj, mes_id): args = dict() mes_status = "ACTIVE" ns_status = "PENDING_CREATE" vnffg_status = "PENDING_CREATE" mec_status = "PENDING_CREATE" ns_retries = NS_RETRIES mec_retries = MEC_RETRIES vnffg_retries = VNFFG_RETRIES mes_mapping = self.get_mes(context, mes_id)['mes_mapping'] # Check MECA meca_id = mes_mapping['MECA'] while mec_status == "PENDING_CREATE" and mec_retries > 0: time.sleep(MEC_RETRY_WAIT) mec_status = meo_plugin.get_meca(context, meca_id)['status'] LOG.debug('status: %s', mec_status) if mec_status == 'ACTIVE' or mec_status == 'ERROR': break mec_retries = mec_retries - 1 error_reason = None if mec_retries == 0 and mec_status == 'PENDING_CREATE': error_reason = _( "MES creation is not completed within" " {wait} seconds as creation of MECA").format( wait=MEC_RETRIES * MEC_RETRY_WAIT) # Check NS/VNFFG status if mes_mapping.get('NS'): ns_list = mes_mapping['NS'] while ns_status == "PENDING_CREATE" and ns_retries > 0: time.sleep(NS_RETRY_WAIT) # Todo: support multiple NSs ns_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_get', ns_id=ns_list[0], auth_attr=vim_res['vim_auth'], ) ns_status = ns_instance['status'] LOG.debug('status: %s', ns_status) if ns_status == 'ACTIVE' or ns_status == 'ERROR': break ns_retries = ns_retries - 1 error_reason = None if ns_retries == 0 and ns_status == 'PENDING_CREATE': error_reason = _( "MES creation is not completed within" " {wait} seconds as creation of NS(s)").format( wait=NS_RETRIES * NS_RETRY_WAIT) # Determine args ns_cd = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_get', ns_id=ns_list[0], auth_attr=vim_res['vim_auth'], ) ns_instance_dict = ns_cd['mgmt_urls'] ns_instance_list = ast.literal_eval(ns_instance_dict) args['NS'] = dict() for vnf_name, mgmt_url_list in ns_instance_list.items(): # Todo: remember to change this with VM capacity vm_capacity = VM_CAPA[vnf_name] orig = [vm_capacity] * len(mgmt_url_list) args['NS'][vnf_name] = [(val - 1) for val in orig] if mes_mapping.get('VNFFG'): while vnffg_status == "PENDING_CREATE" and vnffg_retries > 0: time.sleep(VNFFG_RETRY_WAIT) vnffg_list = mes_mapping['VNFFG'] # Todo: support multiple VNFFGs vnffg_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'vnffg_get', vnffg_id=vnffg_list[0], auth_attr=vim_res['vim_auth'], ) vnffg_status = vnffg_instance['status'] LOG.debug('status: %s', vnffg_status) if vnffg_status == 'ACTIVE' or vnffg_status == 'ERROR': break vnffg_retries = vnffg_retries - 1 error_reason = None if vnffg_retries == 0 and vnffg_status == 'PENDING_CREATE': error_reason = _( "MES creation is not completed within" " {wait} seconds as creation of VNFFG(s)").format( wait=VNFFG_RETRIES * VNFFG_RETRY_WAIT) if mec_status == "ERROR" or ns_status == "ERROR" or vnffg_status == "ERROR": # noqa mes_status = "ERROR" if error_reason: mes_status = "PENDING_CREATE" super(MesoPlugin, self).create_mes_post(context, mes_id, mes_status, error_reason, args) # noqa self.spawn_n(_create_mes_wait, self, mes_dict['id']) return mes_dict
def create_mes(self, context, mes): """Create MES and corresponding MEAs. :param mes: mes dict which contains mesd_id and attributes This method has 2 steps: step-1: Call MEO API to create MEAs step-2: Call Tacker drivers to create NSs """ mes_info = mes['mes'] name = mes_info['name'] mes_info['mes_mapping'] = dict() if mes_info.get('mesd_template'): mesd_name = utils.generate_resource_name(name, 'inline') mesd = {'mesd': { 'attributes': {'mesd': mes_info['mesd_template']}, 'description': mes_info['description'], 'name': mesd_name, 'template_source': 'inline', 'tenant_id': mes_info['tenant_id']}} mes_info['mesd_id'] = self.create_mesd(context, mesd).get('id') mesd = self.get_mesd(context, mes['mes']['mesd_id']) mesd_dict = yaml.safe_load(mesd['attributes']['mesd']) meo_plugin = manager.ApmecManager.get_service_plugins()['MEO'] region_name = mes.setdefault('placement_attr', {}).get( 'region_name', None) vim_res = self.vim_client.get_vim(context, mes['mes']['vim_id'], region_name) driver_type = vim_res['vim_type'] if not mes['mes']['vim_id']: mes['mes']['vim_id'] = vim_res['vim_id'] ########################################## # Detect MANO driver here: # Defined in the Tosca template nfv_driver = None if mesd_dict['imports'].get('nsds'): nfv_driver = mesd_dict['imports']['nsds']['nfv_driver'] nfv_driver = nfv_driver.lower() if mesd_dict['imports'].get('vnffgds'): nfv_driver = mesd_dict['imports']['vnffgds']['nfv_driver'] nfv_driver = nfv_driver.lower() ########################################## def _find_vnf_ins(cd_mes): al_ns_id_list = cd_mes['mes_mapping'].get('NS') if not al_ns_id_list: return None, None al_ns_id = al_ns_id_list[0] try: ns_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_get', ns_id=al_ns_id, auth_attr=vim_res['vim_auth'], ) except: return None, None if ns_instance['status'] != 'ACTIVE': return None, None al_vnf = ns_instance['vnf_ids'] al_vnf_dict = ast.literal_eval(al_vnf) return ns_instance['id'], al_vnf_dict def _generic_ns_set(req_vnf_list): al_mes_list = self.get_mess(context) ns_candidate = dict() for al_mes in al_mes_list: if al_mes['status'] != "ACTIVE": continue ns_candidate[al_mes['id']] = dict() al_ns_id, al_vnf_dict = _find_vnf_ins(al_mes) if not al_ns_id: continue ns_candidate[al_mes['id']] = dict() for req_vnf_dict in req_vnf_list: for vnf_name, al_vnf_id in al_vnf_dict.items(): if req_vnf_dict['name'] == vnf_name: # Todo: remember to change this with VM capacity len_diff = len([lend for lend in al_mes['reused'][vnf_name] if lend > 0]) avail = len_diff - req_vnf_dict['nf_ins'] ns_candidate[al_mes['id']].update({vnf_name: avail}) # The rest will be treated differently by the algorithms return ns_candidate def _run_meso_rsfca(req_vnf_list, ns_candidate=None): rsfca_is_accepted = False required_info_dict = dict() if not ns_candidate: ns_candidate = _generic_ns_set(req_nf_list) ns_cds = dict() deep_ns = dict() for ck_mes_id, ns_data_dict in ns_candidate.items(): # This is the heart of the rvnfa if len(ns_data_dict) == len(req_vnf_list): nf_ins_list = [nf_ins for nf_name, nf_ins in ns_data_dict.items() if nf_ins >= 0] if len(nf_ins_list) == len(req_vnf_list): total_ins = sum(nf_ins_list) ns_cds[ck_mes_id] = total_ins else: extra_nf_ins_list = [-nf_ins for nf_name, nf_ins in ns_data_dict.items() if nf_ins < 0] total_ins = sum(extra_nf_ins_list) deep_ns[ck_mes_id] = total_ins if ns_cds: selected_mes1 = min(ns_cds, key=ns_cds.get) required_info_dict[selected_mes1] = ns_candidate[selected_mes1] rsfca_is_accepted = True if deep_ns: selected_mes2 = min(deep_ns, key=deep_ns.get) required_info_dict[selected_mes2] = ns_candidate[selected_mes2] rsfca_is_accepted = True return rsfca_is_accepted, required_info_dict def _run_meso_rvnfa(req_vnf_list): rvnfa_remain_list = list() rvnfa_is_accepted = False rvnfa_required_info = dict() final_candidate = dict() # Consider using the OrderDict ns_candidate = _generic_ns_set(req_vnf_list) if not ns_candidate: return rvnfa_is_accepted, None, req_vnf_list for req_vnf_dict in req_vnf_list: req_vnf_name = req_vnf_dict['name'] candidate_set = list() for ck_mes_id, mes_data_dict in ns_candidate.items(): if req_vnf_name in mes_data_dict: slots = mes_data_dict[req_vnf_name] candidate_set.append({'mes_id': ck_mes_id, 'slots': slots}) exp_slot_list = [mes_candidate['slots'] for mes_candidate in candidate_set if mes_candidate['slots'] >= 0] # noqa if exp_slot_list: min_slot = min(exp_slot_list) mes_list =\ [mes_candidate['mes_id'] for mes_candidate in candidate_set if mes_candidate['slots'] == min_slot] # noqa final_candidate[req_vnf_name] = {'mes_id':mes_list[0], 'slots':min_slot} if len(final_candidate) == len(req_nf_list): rvnfa_is_accepted = True else: for remain_vnf_dict in req_nf_list: if remain_vnf_dict['name'] not in final_candidate: rvnfa_remain_list.append(remain_vnf_dict) # good one for req_vnf_name, mixed_mes_info in final_candidate: orig_mes_id = mixed_mes_info['mes_id'] nf_slots = mixed_mes_info['slots'] if orig_mes_id not in rvnfa_required_info: rvnfa_required_info[orig_mes_id] = dict() rvnfa_required_info[orig_mes_id].update({req_vnf_name: nf_slots}) else: rvnfa_required_info[orig_mes_id].update({req_vnf_name: nf_slots}) # return the list of NSs must be updated, when to create new mes? return rvnfa_is_accepted, rvnfa_required_info, rvnfa_remain_list def _run_meso_ha(req_vnf_list): final_candidate_id = None ha_required_info = dict() ha_remain_list = list() ha_is_accepted = False ns_candidate = _generic_ns_set(req_vnf_list) if not ns_candidate: return ha_is_accepted, None, req_nf_list ha_is_accepted, ha_mes_dict = _run_meso_rsfca(req_nf_list, ns_candidate) if ha_is_accepted: return ha_is_accepted, ha_mes_dict, None else: ns_list = list() for ck_mes_id, mes_data_dict in ns_candidate.items(): lenNF = len(mes_data_dict) ns_list.append({'mes_id': ck_mes_id, 'numNFs': lenNF}) maxNFs = max([ns_info['numNFs'] for ns_info in ns_list]) first_filter_list = list() second_filter_list = list() for ns_info in ns_list: if ns_info['numNFs'] == maxNFs: mes_id = ns_info['mes_id'] exp_NFs = [slots for exp_vnf_name, slots in ns_candidate[mes_id].items() if slots >= 0] unexp_NFs = [-slots for exp_vnf_name, slots in ns_candidate[mes_id].items() if slots < 0] if len(exp_NFs) == maxNFs: first_filter_list.append( {'mes_id': mes_id, 'slots': sum(exp_NFs)}) else: second_filter_list.append( {'mes_id': mes_id, 'slots': sum(unexp_NFs)}) if first_filter_list: exp_slot = min([exp_mes['slots'] for exp_mes in first_filter_list]) exp_mes_list = [exp_mes['mes_id'] for exp_mes in first_filter_list if exp_mes['slots'] == exp_slot] final_candidate_id = exp_mes_list[0] if second_filter_list: unexp_slot = min([exp_mes['slots'] for exp_mes in second_filter_list]) exp_mes_list = [exp_mes['mes_id'] for exp_mes in second_filter_list if exp_mes['slots'] == unexp_slot] final_candidate_id = exp_mes_list[0] if final_candidate_id: ha_required_info[final_candidate_id] = ns_candidate[final_candidate_id] rvnf_remain_list = [exp_vnf_dict for exp_vnf_dict in req_vnf_list if exp_vnf_dict['name'] not in ns_candidate[final_candidate_id]] # noqa vnf_is_accepted, rvnf_required_info, rvnf_remain_list = _run_meso_rvnfa(rvnf_remain_list) ha_remain_list.extend(rvnf_remain_list) ha_required_info.update(rvnf_required_info) # only return the mes_id and the mes_info need to update return ha_is_accepted, ha_required_info, ha_remain_list build_nsd_dict = dict() if mesd_dict['imports'].get('nsds'): # For framework evaluation nsd_template = mesd_dict['imports']['nsds']['nsd_templates'] if isinstance(nsd_template, dict): if nsd_template.get('requirements'): req_nf_dict = nsd_template['requirements'] req_nf_list = list() for vnf_dict in req_nf_dict: # Todo: make the requests more natural req_nf_list.append({'name': vnf_dict['name'], 'nf_ins': int(vnf_dict['vnfd_template'][5])}) is_accepted, mes_info_dict = _run_meso_rsfca(req_nf_list) if is_accepted: update_list = list() for cd_mes_id, mes_dict in mes_info_dict.items(): new_mesd_dict = dict() ref_mesd_dict = copy.deepcopy(mesd_dict) ref_mesd_dict['imports']['nsds']['nsd_templates']['requirements'] = mes_dict new_mesd_dict['mes'] = dict() new_mesd_dict['mes'] = {'mesd_template': yaml.safe_dump(ref_mesd_dict)} return self.update_mes(context,cd_mes_id, new_mesd_dict) # update_list.append(cd_mes_id) # return {} else: # Create the inline NS with the following template import_list = list() node_dict = dict() for vnfd in req_nf_dict: import_list.append(vnfd['vnfd_template']) node = 'tosca.nodes.nfv.' + vnfd['name'] node_dict[vnfd['name']] = {'type': node} build_nsd_dict['tosca_definitions_version'] = 'tosca_simple_profile_for_nfv_1_0_0' build_nsd_dict['description'] = mes_info['description'] build_nsd_dict['imports'] = import_list build_nsd_dict['topology_template'] = dict() build_nsd_dict['topology_template']['node_templates'] = node_dict # Temp update the new NFs # For these cases, remember when to update the MEA ha_is_accepted, required_info, remain_list = _run_meso_ha(req_nf_list) rvnfa_is_accepted, required_info, remain_list = _run_meso_rvnfa(req_nf_list) if required_info: update_list = list() for cd_mes_id, mes_dict in required_info.items(): new_mesd_dict = dict() ref_mesd_dict = copy.deepcopy(mesd_dict) ref_mesd_dict['imports']['nsds']['nsd_templates']['requirements'] = mes_dict new_mesd_dict['mes'] = dict() new_mesd_dict['mes'] = {'mesd_template': yaml.safe_dump(ref_mesd_dict)} self.update_mes(context, cd_mes_id, new_mesd_dict) update_list.append(cd_mes_id) if not remain_list: return {} if remain_list: # reform the vnf_dict vnf_info_tpl = list() for vnf_dict in remain_list: vnf_ins = vnf_dict['nf_ins'] node_name = vnf_dict['name'] vnfd_tpl = 'vnfd' + node_name[3] + str(vnf_ins) vnf_info_tpl.append({'name': node_name, 'vnfd_template': vnfd_tpl}) import_list = list() node_dict = dict() for vnfd in vnf_info_tpl: import_list.append(vnfd['vnfd_template']) node = 'tosca.nodes.nfv.' + vnfd['name'] node_dict[vnfd['name']] = {'type': node} build_nsd_dict['tosca_definitions_version'] = 'tosca_simple_profile_for_nfv_1_0_0' build_nsd_dict['description'] = mes_info['description'] build_nsd_dict['imports'] = import_list build_nsd_dict['topology_template'] = dict() build_nsd_dict['topology_template']['node_templates'] = node_dict nsds = mesd['attributes'].get('nsds') mes_info['mes_mapping']['NS'] = list() if nsds: nsds_list = nsds.split('-') for nsd in nsds_list: ns_name = nsd + '-' + name + '-' + uuidutils.generate_uuid() nsd_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'nsd_get_by_name', nsd_name=nsd, auth_attr=vim_res['vim_auth'],) if nsd_instance: ns_arg = {'ns': {'nsd_id': nsd_instance['id'], 'name': ns_name}} ns_id = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_create', ns_dict=ns_arg, auth_attr=vim_res['vim_auth'], ) mes_info['mes_mapping']['NS'].append(ns_id) if build_nsd_dict: ns_name = 'nsd' + name + '-' + uuidutils.generate_uuid() ns_arg = {'ns': {'nsd_template': build_nsd_dict, 'name': ns_name, 'description': mes_info['description'], 'vim_id': '', 'tenant_id': mes_info['tenant_id'], 'attributes': {}}} ns_id = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_create', ns_dict=ns_arg, auth_attr=vim_res['vim_auth'], ) mes_info['mes_mapping']['NS'].append(ns_id) vnffgds = mesd['attributes'].get('vnffgds') if mesd_dict['imports'].get('vnffgds'): vnffgds_list = vnffgds.split('-') mes_info['mes_mapping']['VNFFG'] = list() for vnffgd in vnffgds_list: vnffg_name = vnffgds + '-' + name + '-' + uuidutils.generate_uuid() vnffgd_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'vnffgd_get_by_name', vnffgd_name=vnffgd, auth_attr=vim_res['vim_auth'], ) if vnffgd_instance: vnffg_arg = {'vnffg': {'vnffgd_id': vnffgd_instance['id'], 'name': vnffg_name}} vnffg_id = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'vnffg_create', vnffg_dict=vnffg_arg, auth_attr=vim_res['vim_auth'], ) mes_info['mes_mapping']['VNFFG'].append(vnffg_id) meca_id = dict() # Create MEAs using MEO APIs try: meca_name = 'meca' + '-' + name + '-' + uuidutils.generate_uuid() # Separate the imports out from template mead_tpl_dict = dict() mead_tpl_dict['imports'] = mesd_dict['imports']['meads']['mead_templates'] mecad_dict = copy.deepcopy(mesd_dict) mecad_dict.pop('imports') mecad_dict.update(mead_tpl_dict) LOG.debug('mesd %s', mecad_dict) meca_arg = {'meca': {'mecad_template': mecad_dict, 'name': meca_name, 'description': mes_info['description'], 'tenant_id': mes_info['tenant_id'], 'vim_id': mes_info['vim_id'], 'attributes': {}}} meca_dict = meo_plugin.create_meca(context, meca_arg) mes_info['mes_mapping']['MECA'] = meca_dict['id'] except Exception as e: LOG.error('Error while creating the MECAs: %s', e) # Call Tacker client driver mes_dict = super(MesoPlugin, self).create_mes(context, mes) def _create_mes_wait(self_obj, mes_id): args = dict() mes_status = "ACTIVE" ns_status = "PENDING_CREATE" vnffg_status = "PENDING_CREATE" mec_status = "PENDING_CREATE" ns_retries = NS_RETRIES mec_retries = MEC_RETRIES vnffg_retries = VNFFG_RETRIES mes_mapping = self.get_mes(context, mes_id)['mes_mapping'] # Check MECA meca_id = mes_mapping['MECA'] while mec_status == "PENDING_CREATE" and mec_retries > 0: time.sleep(MEC_RETRY_WAIT) mec_status = meo_plugin.get_meca(context, meca_id)['status'] LOG.debug('status: %s', mec_status) if mec_status == 'ACTIVE' or mec_status == 'ERROR': break mec_retries = mec_retries - 1 error_reason = None if mec_retries == 0 and mec_status == 'PENDING_CREATE': error_reason = _( "MES creation is not completed within" " {wait} seconds as creation of MECA").format( wait=MEC_RETRIES * MEC_RETRY_WAIT) # Check NS/VNFFG status if mes_mapping.get('NS'): ns_list = mes_mapping['NS'] while ns_status == "PENDING_CREATE" and ns_retries > 0: time.sleep(NS_RETRY_WAIT) # Todo: support multiple NSs ns_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_get', ns_id=ns_list[0], auth_attr=vim_res['vim_auth'], ) ns_status = ns_instance['status'] LOG.debug('status: %s', ns_status) if ns_status == 'ACTIVE' or ns_status == 'ERROR': break ns_retries = ns_retries - 1 error_reason = None if ns_retries == 0 and ns_status == 'PENDING_CREATE': error_reason = _( "MES creation is not completed within" " {wait} seconds as creation of NS(s)").format( wait=NS_RETRIES * NS_RETRY_WAIT) # Determine args ns_cd = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'ns_get', ns_id=ns_list[0], auth_attr=vim_res['vim_auth'], ) ns_instance_dict = ns_cd['mgmt_urls'] ns_instance_list = ast.literal_eval(ns_instance_dict) args['NS'] = dict() for vnf_name, mgmt_url_list in ns_instance_list.items(): # Todo: remember to change this with VM capacity vm_capacity = VM_CAPA[vnf_name] orig = [vm_capacity] * len(mgmt_url_list) args['NS'][vnf_name] = [(val - 1) for val in orig] if mes_mapping.get('VNFFG'): while vnffg_status == "PENDING_CREATE" and vnffg_retries > 0: time.sleep(VNFFG_RETRY_WAIT) vnffg_list = mes_mapping['VNFFG'] # Todo: support multiple VNFFGs vnffg_instance = self._nfv_drivers.invoke( nfv_driver, # How to tell it is Tacker 'vnffg_get', vnffg_id=vnffg_list[0], auth_attr=vim_res['vim_auth'], ) vnffg_status = vnffg_instance['status'] LOG.debug('status: %s', vnffg_status) if vnffg_status == 'ACTIVE' or vnffg_status == 'ERROR': break vnffg_retries = vnffg_retries - 1 error_reason = None if vnffg_retries == 0 and vnffg_status == 'PENDING_CREATE': error_reason = _( "MES creation is not completed within" " {wait} seconds as creation of VNFFG(s)").format( wait=VNFFG_RETRIES * VNFFG_RETRY_WAIT) if mec_status == "ERROR" or ns_status == "ERROR" or vnffg_status == "ERROR": mes_status = "ERROR" if error_reason: mes_status = "PENDING_CREATE" super(MesoPlugin, self).create_mes_post(context, mes_id, mes_status, error_reason, args) self.spawn_n(_create_mes_wait, self, mes_dict['id']) return mes_dict