package service import ( "encoding/json" "fmt" "os" "runtime" "strings" "be.ems/src/framework/constants/cachekey" "be.ems/src/framework/logger" "be.ems/src/framework/redis" "be.ems/src/framework/utils/ssh" "be.ems/src/modules/network_element/model" "be.ems/src/modules/network_element/repository" ) // 实例化服务层 NeInfoImpl 结构体 var NewNeInfoImpl = &NeInfoImpl{ neInfoRepository: repository.NewNeInfoImpl, neHostRepository: repository.NewNeHostImpl, } // 网元信息 服务层处理 type NeInfoImpl struct { // 网元信息数据信息 neInfoRepository repository.INeInfo // 网元主机连接表 neHostRepository repository.INeHost } // SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息 func (r *NeInfoImpl) SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo { var neInfo model.NeInfo key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, strings.ToUpper(neType), neID) jsonStr, _ := redis.Get("", key) if len(jsonStr) > 7 { err := json.Unmarshal([]byte(jsonStr), &neInfo) if err != nil { neInfo = model.NeInfo{} } } else { neInfo = r.neInfoRepository.SelectNeInfoByNeTypeAndNeID(neType, neID) if neInfo.NeId == neID { redis.Del("", key) values, _ := json.Marshal(neInfo) redis.Set("", key, string(values)) } } return neInfo } // RefreshByNeTypeAndNeID 通过ne_type和ne_id刷新redis中的缓存 func (r *NeInfoImpl) RefreshByNeTypeAndNeID(neType, neID string) model.NeInfo { var neInfo model.NeInfo key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, strings.ToUpper(neType), neID) redis.Del("", key) neInfo = r.neInfoRepository.SelectNeInfoByNeTypeAndNeID(neType, neID) if neInfo.NeId == neID { values, _ := json.Marshal(neInfo) redis.Set("", key, string(values)) } return neInfo } // ClearNeCacheByNeType 清除网元类型缓存 func (r *NeInfoImpl) ClearNeCacheByNeType(neType string) bool { key := fmt.Sprintf("%s*", cachekey.NE_KEY) if neType != "*" { key = fmt.Sprintf("%s%s*", cachekey.NE_KEY, neType) } keys, err := redis.GetKeys("", key) if err != nil { return false } delOk, _ := redis.DelKeys("", keys) return delOk } // SelectNeInfoByRmuid 通过rmUID查询网元信息 func (r *NeInfoImpl) SelectNeInfoByRmuid(rmUid string) model.NeInfo { var neInfo model.NeInfo cacheKeys, _ := redis.GetKeys("", cachekey.NE_KEY+"*") if len(cacheKeys) > 0 { for _, key := range cacheKeys { var v model.NeInfo jsonStr, _ := redis.Get("", key) if len(jsonStr) > 7 { json.Unmarshal([]byte(jsonStr), &v) } if v.RmUID == rmUid { neInfo = v break } } } else { neInfos := r.SelectList(neInfo, false) for _, v := range neInfos { key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, strings.ToUpper(v.NeType), v.NeId) redis.Del("", key) values, _ := json.Marshal(v) redis.Set("", key, string(values)) if v.RmUID == rmUid { neInfo = v } } } return neInfo } // SelectPage 根据条件分页查询 // // bandStatus 带状态信息 func (r *NeInfoImpl) SelectPage(query map[string]any, bandStatus bool) map[string]any { data := r.neInfoRepository.SelectPage(query) // 网元直连读取网元服务状态 if bandStatus { rows := data["rows"].([]model.NeInfo) arr := &rows for i := range *arr { v := (*arr)[i] result, err := NeState(v) if err != nil { (*arr)[i].ServerState = map[string]any{ "online": false, } // 网元状态设置为离线 if v.Status != "1" { v.Status = "1" (*arr)[i].Status = v.Status r.neInfoRepository.Update(v) } continue } result["online"] = true (*arr)[i].ServerState = result // 网元状态设置为在线 if v.Status != "0" { // 下发网管配置信息给网元 _, err = NeConfigOMC(v) if err != nil { v.Status = "3" } else { v.Status = "0" } (*arr)[i].Status = v.Status r.neInfoRepository.Update(v) } } } return data } // SelectList 查询列表 // // bandStatus 带状态信息 func (r *NeInfoImpl) SelectList(ne model.NeInfo, bandStatus bool) []model.NeInfo { list := r.neInfoRepository.SelectList(ne) // 网元直连读取网元服务状态 if bandStatus { neList := &list for i := range *neList { v := (*neList)[i] result, err := NeState(v) if err != nil { (*neList)[i].ServerState = map[string]any{ "online": false, } // 网元状态设置为离线 if v.Status != "1" { v.Status = "1" (*neList)[i].Status = v.Status r.neInfoRepository.Update(v) } continue } result["online"] = true (*neList)[i].ServerState = result // 网元状态设置为在线 if v.Status != "0" { // 下发网管配置信息给网元 _, err = NeConfigOMC(v) if err != nil { v.Status = "3" } else { v.Status = "0" } (*neList)[i].Status = v.Status r.neInfoRepository.Update(v) } } } return list } // SelectByIds 通过ID查询 // // bandStatus 带主机信息 func (r *NeInfoImpl) SelectById(infoId string, bandHost bool) model.NeInfo { if infoId == "" { return model.NeInfo{} } neInfos := r.neInfoRepository.SelectByIds([]string{infoId}) if len(neInfos) > 0 { neInfo := neInfos[0] // 带主机信息 if neInfo.HostIDs != "" && bandHost { neInfo.Hosts = r.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) } return neInfo } return model.NeInfo{} } // Insert 新增信息 func (r *NeInfoImpl) Insert(neInfo model.NeInfo) string { // 主机信息新增 if neInfo.Hosts != nil { var hostIDs []string for _, host := range neInfo.Hosts { host.Title = fmt.Sprintf("%s_%s_%d", strings.ToUpper(neInfo.NeType), neInfo.NeId, host.Port) host.GroupID = "1" hostId := r.neHostRepository.Insert(host) if hostId != "" { hostIDs = append(hostIDs, hostId) } } neInfo.HostIDs = strings.Join(hostIDs, ",") } insertId := r.neInfoRepository.Insert(neInfo) if insertId != "" { // 刷新缓存 r.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) } return insertId } // Update 修改信息 func (r *NeInfoImpl) Update(neInfo model.NeInfo) int64 { // 主机信息更新 if neInfo.Hosts != nil { for _, host := range neInfo.Hosts { if host.HostID != "" { host.Title = fmt.Sprintf("%s_%s_%d", strings.ToUpper(neInfo.NeType), neInfo.NeId, host.Port) host.GroupID = "1" r.neHostRepository.Update(host) } } } num := r.neInfoRepository.Update(neInfo) if num > 0 { // 刷新缓存 r.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) } return num } // DeleteByIds 批量删除信息 func (r *NeInfoImpl) DeleteByIds(infoIds []string) (int64, error) { // 检查是否存在 infos := r.neInfoRepository.SelectByIds(infoIds) if len(infos) <= 0 { return 0, fmt.Errorf("neHostCmd.noData") } if len(infos) == len(infoIds) { for _, v := range infos { // 主机信息删除 if v.HostIDs != "" { hostIds := strings.Split(v.HostIDs, ",") r.neHostRepository.DeleteByIds(hostIds) } // 缓存信息删除 key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, v.NeType, v.NeId) redis.Del("", key) } rows := r.neInfoRepository.DeleteByIds(infoIds) return rows, nil } // 删除信息失败! return 0, fmt.Errorf("delete fail") } // CheckUniqueNeTypeAndNeId 校验同类型下标识是否唯一 func (r *NeInfoImpl) CheckUniqueNeTypeAndNeId(neType, neId, infoId string) bool { uniqueId := r.neInfoRepository.CheckUniqueNeTypeAndNeId(model.NeInfo{ NeType: neType, NeId: neId, }) if uniqueId == infoId { return true } return uniqueId == "" } // NeRunCMD 向网元发送cmd命令 func (r *NeInfoImpl) NeRunCMD(neType, neId, cmd string) (string, error) { neInfo := r.SelectNeInfoByNeTypeAndNeID(neType, neId) if neInfo.NeId != neId { logger.Errorf("NeRunCMD NeType:%s NeID:%s not found", neType, neId) return "", fmt.Errorf("neinfo not found") } // 带主机信息 if neInfo.HostIDs != "" { neInfo.Hosts = r.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) if len(neInfo.Hosts) <= 0 { logger.Errorf("NeRunCMD Hosts %s not found", neInfo.HostIDs) return "", fmt.Errorf("neinfo host not found") } } neHost := neInfo.Hosts[0] if neHost.HostType != "ssh" { logger.Errorf("NeRunCMD Hosts first HostType %s not ssh", neHost.HostType) return "", fmt.Errorf("neinfo host type not ssh") } var connSSH ssh.ConnSSH neHost.CopyTo(&connSSH) client, err := connSSH.NewClient() if err != nil { logger.Errorf("NeRunCMD NewClient err => %s", err.Error()) return "", fmt.Errorf("neinfo ssh client new err") } defer client.Close() // 执行命令 output, err := client.RunCMD(cmd) if err != nil { logger.Errorf("NeRunCMD RunCMD %s err => %s", output, err.Error()) return "", fmt.Errorf("neinfo ssh run cmd err") } return output, nil } // NeConfigFileRead 网元配置文件读取 网元配置yaml文件复制到本地后通过filePath读取 func (r *NeInfoImpl) NeConfigFileRead(neInfo model.NeInfo, filePath string) []string { files := []string{} neTypeLower := strings.ToLower(neInfo.NeType) // 网管本地路径 omcPath := "/usr/local/etc/omc/ne_config" if runtime.GOOS == "windows" { omcPath = fmt.Sprintf("C:%s", omcPath) } omcPath = fmt.Sprintf("%s/%s/%s", omcPath, neTypeLower, neInfo.NeId) // 读取文件内容 if filePath != "" { bytes, err := os.ReadFile(fmt.Sprintf("%s/%s", omcPath, filePath)) if err != nil { logger.Warnf("NeConfigFile ReadFile => %s", err.Error()) return files } files = append(files, string(bytes)) return files } // 删除原有配置文件 // err := os.RemoveAll(omcPath) // if err != nil { // logger.Warnf("NeConfigFile Remove => %s", err.Error()) // return files // } // 网元端配置路径 nePath := "/usr/local/etc" nePath = fmt.Sprintf("%s/%s", nePath, neTypeLower) // 各个网元与网元间约定配置文件 err := ssh.FileSCPNeToLocal(neInfo.IP, nePath+"/oam_manager.yaml", omcPath+"/oam_manager.yaml") if err == nil { files = append(files, "oam_manager.yaml") } // 根据情况复制网元特殊配置 switch neTypeLower { case "ausf": err = ssh.FileSCPNeToLocal(neInfo.IP, nePath+"/ausfcfg.yaml", omcPath+"/ausfcfg.yaml") if err == nil { files = append(files, "ausfcfg.yaml") } case "smf": ssh.FileSCPNeToLocal(neInfo.IP, nePath+"/smf_conf.yaml", omcPath+"/smf_conf.yaml") if err == nil { files = append(files, "smf_conf.yaml") } ssh.FileSCPNeToLocal(neInfo.IP, nePath+"/smf_policy.yaml", omcPath+"/smf_policy.yaml") if err == nil { files = append(files, "smf_policy.yaml") } case "ims": } return files } // NeConfigFileWirte 网元配置文件写入 content内容 sync同步到网元端 func (r *NeInfoImpl) NeConfigFileWirte(neInfo model.NeInfo, filePath, content string, sync bool) error { neTypeLower := strings.ToLower(neInfo.NeType) // 网管本地路径 omcPath := "/usr/local/etc/omc/ne_config" if runtime.GOOS == "windows" { omcPath = fmt.Sprintf("C:%s", omcPath) } localFilePath := fmt.Sprintf("%s/%s/%s/%s", omcPath, neTypeLower, neInfo.NeId, filePath) err := os.WriteFile(localFilePath, []byte(content), 0644) if err != nil { logger.Warnf("NeConfigFile WriteFile => %s", err.Error()) return fmt.Errorf("please check if the file exists or write permissions") } // 同步到网元端 if sync { // 网元端配置路径 neFilePath := fmt.Sprintf("/usr/local/etc/%s/%s", neTypeLower, filePath) // 修改网元文件权限 r.NeRunCMD(neInfo.NeType, neInfo.NeId, fmt.Sprintf("sudo chmod o+w %s", neFilePath)) // 复制到网元进行覆盖 err = ssh.FileSCPLocalToNe(neInfo.IP, localFilePath, neFilePath) if err != nil { logger.Warnf("NeConfigFile SyncFile => %s", err.Error()) return fmt.Errorf("please check if scp remote copy is allowed") } } return nil }