From bc599ec5b0800473e1ec6473d44ce4a72569501d Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Thu, 11 Apr 2024 17:13:54 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BD=91=E5=85=83=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9B=B4=E6=96=B0=E5=90=8C=E6=AD=A5=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E7=89=88=E6=9C=AC=E5=92=8C=E6=8E=88=E6=9D=83=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../network_element/controller/ne_info.go | 115 +++++++++++--- src/modules/network_element/model/ne_info.go | 11 +- .../repository/ne_info.impl.go | 21 ++- .../network_element/service/ne_info.go | 12 +- .../network_element/service/ne_info.impl.go | 140 +++++++++++------- 5 files changed, 209 insertions(+), 90 deletions(-) diff --git a/src/modules/network_element/controller/ne_info.go b/src/modules/network_element/controller/ne_info.go index 55c10c3f..a204572e 100644 --- a/src/modules/network_element/controller/ne_info.go +++ b/src/modules/network_element/controller/ne_info.go @@ -17,15 +17,21 @@ import ( // 实例化控制层 NeInfoController 结构体 var NewNeInfo = &NeInfoController{ - neInfoService: neService.NewNeInfoImpl, + neInfoService: neService.NewNeInfoImpl, + neLicenseService: neService.NewNeLicenseImpl, + neVersionService: neService.NewNeVersionImpl, } // 网元信息请求 // -// PATH / +// PATH /info type NeInfoController struct { // 网元信息服务 neInfoService neService.INeInfo + // 网元授权激活信息服务 + neLicenseService neService.INeLicense + // 网元版本信息服务 + neVersionService neService.INeVersion } // neStateCacheMap 网元状态缓存最后一次成功的信息 @@ -146,7 +152,8 @@ func (s *NeInfoController) ConfigFileRead(c *gin.Context) { var querys struct { NeType string `form:"neType" binding:"required"` NeID string `form:"neId" binding:"required"` - FilePath string `form:"filePath"` // 不带文件路径时进行复制覆盖本地网元配置目录 + FilePath string `form:"filePath"` // 不带文件路径时进行复制覆盖本地网元配置目录 + FileType string `form:"fileType" binding:"oneof='' txt json yaml yml"` // 根据指定文件类型进行解析序列出map->json } if err := c.ShouldBindQuery(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) @@ -160,16 +167,8 @@ func (s *NeInfoController) ConfigFileRead(c *gin.Context) { return } - data := s.neInfoService.NeConfigFileRead(neInfo, querys.FilePath) - if querys.FilePath == "" { - c.JSON(200, result.OkData(data)) - return - } - if len(data) > 0 { - c.JSON(200, result.OkData(data[0])) - return - } - c.JSON(200, result.ErrMsg("no data")) + data := s.neInfoService.NeConfigFileRead(neInfo, querys.FilePath, querys.FileType) + c.JSON(200, result.OkData(data)) } // 网元端配置文件写入 @@ -181,8 +180,9 @@ func (s *NeInfoController) ConfigFileWrite(c *gin.Context) { NeType string `json:"neType" binding:"required"` NeID string `json:"neId" binding:"required"` FilePath string `json:"filePath" binding:"required"` - Content string `json:"content" binding:"required"` - Sync bool `json:"sync"` + FileType string `json:"fileType" binding:"oneof='' txt json yaml yml"` // 解析内容数据到对应文件类型 + Content any `json:"content" binding:"required"` // 内容 + Sync bool `json:"sync"` // 同步到网元 } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) @@ -196,7 +196,7 @@ func (s *NeInfoController) ConfigFileWrite(c *gin.Context) { return } - err := s.neInfoService.NeConfigFileWirte(neInfo, body.FilePath, body.Content, body.Sync) + err := s.neInfoService.NeConfigFileWirte(neInfo, body.FilePath, body.FileType, body.Content, body.Sync) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -260,19 +260,50 @@ func (s *NeInfoController) Add(c *gin.Context) { } // 获取网元状态是否正常 - _, err = neService.NeState(body) + body.ServerState, err = neService.NeState(body) if err != nil { - body.Status = "1" + body.Status = "0" } else { // 下发网管配置信息给网元 _, err = neService.NeConfigOMC(body) if err == nil { - body.Status = "0" + body.Status = "1" } else { - body.Status = "3" + body.Status = "2" } } + loginUserName := ctx.LoginUserToUserName(c) + // 新增Version信息 + neVersion := model.NeVersion{ + NeType: body.NeType, + NeId: body.NeId, + CreateBy: loginUserName, + } + // 新增License信息 + neLicense := model.NeLicense{ + NeType: body.NeType, + NeId: body.NeId, + CreateBy: loginUserName, + } + + // 已有网元可获取的信息 + if body.ServerState != nil { + if v, ok := body.ServerState["version"]; ok && v != nil { + neVersion.Version = v.(string) + } + if v, ok := body.ServerState["sn"]; ok && v != nil { + neLicense.SerialNum = v.(string) + } + if v, ok := body.ServerState["expire"]; ok && v != nil { + neLicense.ExpiryDate = v.(string) + neLicense.Status = "1" + } + } + + s.neVersionService.Insert(neVersion) + s.neLicenseService.Insert(neLicense) + body.UpdateBy = loginUserName insertId := s.neInfoService.Insert(body) if insertId != "" { c.JSON(200, result.Ok(nil)) @@ -311,19 +342,55 @@ func (s *NeInfoController) Edit(c *gin.Context) { } // 获取网元状态是否正常 - _, err = neService.NeState(body) + body.ServerState, err = neService.NeState(body) if err != nil { - body.Status = "1" + body.Status = "0" } else { // 下发网管配置信息给网元 _, err = neService.NeConfigOMC(body) if err == nil { - body.Status = "0" + body.Status = "1" } else { - body.Status = "3" + body.Status = "2" } } + loginUserName := ctx.LoginUserToUserName(c) + neLicense := s.neLicenseService.SelectByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) + neVersion := s.neVersionService.SelectByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) + + // 已有网元可获取的信息 + if body.ServerState != nil { + if v, ok := body.ServerState["version"]; ok && v != nil { + neVersion.Version = v.(string) + neVersion.UpdateBy = loginUserName + } + if v, ok := body.ServerState["sn"]; ok && v != nil { + neLicense.SerialNum = v.(string) + } + if v, ok := body.ServerState["expire"]; ok && v != nil { + neLicense.ExpiryDate = v.(string) + neLicense.Status = "1" + neLicense.UpdateBy = loginUserName + } + } + + if neVersion.NeType != body.NeType || neVersion.NeId != body.NeId { + neVersion.NeType = body.NeType + neVersion.NeId = body.NeId + } + if neVersion.ID != "" { + s.neVersionService.Update(neVersion) + } + if neLicense.NeType != body.NeType || neLicense.NeId != body.NeId { + neVersion.NeType = body.NeType + neVersion.NeId = body.NeId + } + if neLicense.ID != "" { + s.neLicenseService.Update(neLicense) + } + + body.UpdateBy = loginUserName rows := s.neInfoService.Update(body) if rows > 0 { c.JSON(200, result.Ok(nil)) diff --git a/src/modules/network_element/model/ne_info.go b/src/modules/network_element/model/ne_info.go index c08e71a0..59ce4b71 100644 --- a/src/modules/network_element/model/ne_info.go +++ b/src/modules/network_element/model/ne_info.go @@ -10,13 +10,14 @@ type NeInfo struct { IP string `json:"ip" binding:"required"` Port int64 `json:"port" binding:"required,number,max=65535,min=1"` PvFlag string `json:"pvFlag" binding:"oneof=PNF VNF"` // enum('PNF','VNF') - Province string `json:"province"` + Province string `json:"province"` // 省份地域 VendorName string `json:"vendorName"` Dn string `json:"dn"` - NeAddress string `json:"neAddress"` - Status string `json:"status"` // 0: 在线 1: 下线 2: 备用 3: 待下发配置 - UpdateTime string `json:"updateTime"` - HostIDs string `json:"hostIds"` // 网元主机ID组 数据格式(ssh,telnet,telnet) + NeAddress string `json:"neAddress"` // MAC地址 + Status string `json:"status"` // 0离线 1在线 2配置待下发 + UpdateBy string `json:"updateBy"` // 更新者 + UpdateTime string `json:"updateTime"` // 更新时间 + HostIDs string `json:"hostIds"` // 网元主机ID组 数据格式(ssh,telnet,telnet) // ====== 非数据库字段属性 ====== diff --git a/src/modules/network_element/repository/ne_info.impl.go b/src/modules/network_element/repository/ne_info.impl.go index 85fdea50..cd06d84a 100644 --- a/src/modules/network_element/repository/ne_info.impl.go +++ b/src/modules/network_element/repository/ne_info.impl.go @@ -34,7 +34,7 @@ var neListSort = []string{ // 实例化数据层 NeInfoImpl 结构体 var NewNeInfoImpl = &NeInfoImpl{ - selectSql: `select id, ne_type, ne_id, rm_uid, ne_name, ip, port, pv_flag, province, vendor_name, dn, ne_address, status, update_time, host_ids from ne_info`, + selectSql: `select id, ne_type, ne_id, rm_uid, ne_name, ip, port, pv_flag, province, vendor_name, dn, ne_address, status, update_time, update_by, host_ids from ne_info`, resultMap: map[string]string{ "id": "ID", @@ -51,6 +51,7 @@ var NewNeInfoImpl = &NeInfoImpl{ "ne_address": "NeAddress", "status": "Status", "update_time": "UpdateTime", + "update_by": "UpdateBy", "host_ids": "HostIDs", }, } @@ -298,8 +299,13 @@ func (r *NeInfoImpl) Insert(neInfo model.NeInfo) string { if neInfo.NeAddress != "" { params["ne_address"] = neInfo.NeAddress } - params["status"] = neInfo.Status - params["update_time"] = time.Now() + if neInfo.Status != "" { + params["status"] = neInfo.Status + } + if neInfo.UpdateBy != "" { + params["update_by"] = neInfo.UpdateBy + params["update_time"] = time.Now().UnixMilli() + } if neInfo.HostIDs != "" { params["host_ids"] = neInfo.HostIDs } @@ -360,8 +366,13 @@ func (r *NeInfoImpl) Update(neInfo model.NeInfo) int64 { params["vendor_name"] = neInfo.VendorName params["dn"] = neInfo.Dn params["ne_address"] = neInfo.NeAddress - params["status"] = neInfo.Status - params["update_time"] = time.Now() + if neInfo.Status != "" { + params["status"] = neInfo.Status + } + if neInfo.UpdateBy != "" { + params["update_by"] = neInfo.UpdateBy + params["update_time"] = time.Now().UnixMilli() + } if neInfo.HostIDs != "" { params["host_ids"] = neInfo.HostIDs } diff --git a/src/modules/network_element/service/ne_info.go b/src/modules/network_element/service/ne_info.go index a667c017..2c523bc9 100644 --- a/src/modules/network_element/service/ne_info.go +++ b/src/modules/network_element/service/ne_info.go @@ -1,6 +1,9 @@ package service -import "be.ems/src/modules/network_element/model" +import ( + "be.ems/src/framework/utils/ssh" + "be.ems/src/modules/network_element/model" +) // 网元信息 服务层接口 type INeInfo interface { @@ -46,9 +49,12 @@ type INeInfo interface { // NeRunCMD 向网元发送cmd命令 NeRunCMD(neType, neId, cmd string) (string, error) + // NeRunSSHclient 网元主机的SSH客户端-为创建相关连接 + NeRunSSHclient(neType, neId string) (*ssh.ConnSSH, error) + // NeConfigFileRead 网元配置文件读取 网元配置yaml文件复制到本地后通过filePath读取 - NeConfigFileRead(neInfo model.NeInfo, filePath string) []string + NeConfigFileRead(neInfo model.NeInfo, filePath, fileType string) any // NeConfigFileWirte 网元配置文件写入 content内容 sync同步到网元端 - NeConfigFileWirte(neInfo model.NeInfo, filePath, content string, sync bool) error + NeConfigFileWirte(neInfo model.NeInfo, filePath, fileType string, content any, sync bool) error } diff --git a/src/modules/network_element/service/ne_info.impl.go b/src/modules/network_element/service/ne_info.impl.go index af2c0bdb..9aef3bce 100644 --- a/src/modules/network_element/service/ne_info.impl.go +++ b/src/modules/network_element/service/ne_info.impl.go @@ -10,6 +10,7 @@ import ( "be.ems/src/framework/constants/cachekey" "be.ems/src/framework/logger" "be.ems/src/framework/redis" + "be.ems/src/framework/utils/parse" "be.ems/src/framework/utils/ssh" "be.ems/src/modules/network_element/model" "be.ems/src/modules/network_element/repository" @@ -18,15 +19,12 @@ import ( // 实例化服务层 NeInfoImpl 结构体 var NewNeInfoImpl = &NeInfoImpl{ neInfoRepository: repository.NewNeInfoImpl, - neHostRepository: repository.NewNeHostImpl, } // 网元信息 服务层处理 type NeInfoImpl struct { // 网元信息数据信息 neInfoRepository repository.INeInfo - // 网元主机连接表 - neHostRepository repository.INeHost } // SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息 @@ -126,8 +124,8 @@ func (r *NeInfoImpl) SelectPage(query map[string]any, bandStatus bool) map[strin "online": false, } // 网元状态设置为离线 - if v.Status != "1" { - v.Status = "1" + if v.Status != "0" { + v.Status = "0" (*arr)[i].Status = v.Status r.neInfoRepository.Update(v) } @@ -136,13 +134,13 @@ func (r *NeInfoImpl) SelectPage(query map[string]any, bandStatus bool) map[strin result["online"] = true (*arr)[i].ServerState = result // 网元状态设置为在线 - if v.Status != "0" { + if v.Status != "1" { // 下发网管配置信息给网元 _, err = NeConfigOMC(v) - if err != nil { - v.Status = "3" + if err == nil { + v.Status = "1" } else { - v.Status = "0" + v.Status = "2" } (*arr)[i].Status = v.Status r.neInfoRepository.Update(v) @@ -170,8 +168,8 @@ func (r *NeInfoImpl) SelectList(ne model.NeInfo, bandStatus bool) []model.NeInfo "online": false, } // 网元状态设置为离线 - if v.Status != "1" { - v.Status = "1" + if v.Status != "0" { + v.Status = "0" (*neList)[i].Status = v.Status r.neInfoRepository.Update(v) } @@ -183,10 +181,10 @@ func (r *NeInfoImpl) SelectList(ne model.NeInfo, bandStatus bool) []model.NeInfo if v.Status != "0" { // 下发网管配置信息给网元 _, err = NeConfigOMC(v) - if err != nil { - v.Status = "3" + if err == nil { + v.Status = "1" } else { - v.Status = "0" + v.Status = "2" } (*neList)[i].Status = v.Status r.neInfoRepository.Update(v) @@ -209,7 +207,7 @@ func (r *NeInfoImpl) SelectById(infoId string, bandHost bool) model.NeInfo { neInfo := neInfos[0] // 带主机信息 if neInfo.HostIDs != "" && bandHost { - neInfo.Hosts = r.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) + neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) } return neInfo } @@ -224,7 +222,7 @@ func (r *NeInfoImpl) Insert(neInfo model.NeInfo) 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) + hostId := NewNeHostImpl.Insert(host) if hostId != "" { hostIDs = append(hostIDs, hostId) } @@ -248,7 +246,7 @@ func (r *NeInfoImpl) Update(neInfo model.NeInfo) int64 { 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) + NewNeHostImpl.Update(host) } } } @@ -274,7 +272,17 @@ func (r *NeInfoImpl) DeleteByIds(infoIds []string) (int64, error) { // 主机信息删除 if v.HostIDs != "" { hostIds := strings.Split(v.HostIDs, ",") - r.neHostRepository.DeleteByIds(hostIds) + NewNeHostImpl.DeleteByIds(hostIds) + } + // 删除License + neLicense := NewNeLicenseImpl.SelectByNeTypeAndNeID(v.NeType, v.NeId) + if neLicense.NeId == v.NeId { + NewNeLicenseImpl.DeleteByIds([]string{neLicense.ID}) + } + // 删除Version + neVersion := NewNeVersionImpl.SelectByNeTypeAndNeID(v.NeType, v.NeId) + if neVersion.NeId == v.NeId { + NewNeVersionImpl.DeleteByIds([]string{neVersion.ID}) } // 缓存信息删除 key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, v.NeType, v.NeId) @@ -301,47 +309,56 @@ func (r *NeInfoImpl) CheckUniqueNeTypeAndNeId(neType, neId, infoId string) bool // 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() + sshClient, err := r.NeRunSSHclient(neType, neId) if err != nil { - logger.Errorf("NeRunCMD NewClient err => %s", err.Error()) - return "", fmt.Errorf("neinfo ssh client new err") + return "", err } - defer client.Close() + defer sshClient.Close() // 执行命令 - output, err := client.RunCMD(cmd) + output, err := sshClient.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 } +// NeRunSSHclient 网元主机的SSH客户端-为创建相关连接 +func (r *NeInfoImpl) NeRunSSHclient(neType, neId string) (*ssh.ConnSSH, error) { + neInfo := r.SelectNeInfoByNeTypeAndNeID(neType, neId) + if neInfo.NeId != neId { + logger.Errorf("NeRunSSHclient NeType:%s NeID:%s not found", neType, neId) + return nil, fmt.Errorf("neinfo not found") + } + // 取主机信息 + if neInfo.HostIDs == "" { + logger.Errorf("NeRunSSHclient NeType:%s NeID:%s hostId not found", neType, neId) + return nil, fmt.Errorf("neinfo hostId not found") + } + neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) + if len(neInfo.Hosts) <= 0 { + logger.Errorf("NeRunSSHclient Hosts %s not found", neInfo.HostIDs) + return nil, fmt.Errorf("neinfo host not found") + } + neHost := neInfo.Hosts[0] + if neHost.HostType != "ssh" { + logger.Errorf("NeRunSSHclient Hosts first HostType %s not ssh", neHost.HostType) + return nil, fmt.Errorf("neinfo host type not ssh") + } + + var connSSH ssh.ConnSSH + neHost.CopyTo(&connSSH) + client, err := connSSH.NewClient() + if err != nil { + logger.Errorf("NeRunSSHclient NewClient err => %s", err.Error()) + return nil, fmt.Errorf("neinfo ssh client new err") + } + return client, nil +} + // NeConfigFileRead 网元配置文件读取 网元配置yaml文件复制到本地后通过filePath读取 -func (r *NeInfoImpl) NeConfigFileRead(neInfo model.NeInfo, filePath string) []string { - files := []string{} +func (r *NeInfoImpl) NeConfigFileRead(neInfo model.NeInfo, filePath, fileType string) any { neTypeLower := strings.ToLower(neInfo.NeType) // 网管本地路径 @@ -356,12 +373,23 @@ func (r *NeInfoImpl) NeConfigFileRead(neInfo model.NeInfo, filePath string) []st bytes, err := os.ReadFile(fmt.Sprintf("%s/%s", omcPath, filePath)) if err != nil { logger.Warnf("NeConfigFile ReadFile => %s", err.Error()) - return files + return "read file error" } - files = append(files, string(bytes)) - return files + content := string(bytes) + if fileType == "" || fileType == "txt" { + return content + } + // 序列化Map + mapData, err := parse.ConvertConfigToMap(fileType, content) + if err != nil { + logger.Warnf("NeConfigFile ConvertConfigToMap => %s", err.Error()) + return "content convert type error" + } + return mapData } + // 文件列表 + files := []string{} // 删除原有配置文件 // err := os.RemoveAll(omcPath) // if err != nil { @@ -373,7 +401,7 @@ func (r *NeInfoImpl) NeConfigFileRead(neInfo model.NeInfo, filePath string) []st 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") @@ -402,7 +430,7 @@ func (r *NeInfoImpl) NeConfigFileRead(neInfo model.NeInfo, filePath string) []st } // NeConfigFileWirte 网元配置文件写入 content内容 sync同步到网元端 -func (r *NeInfoImpl) NeConfigFileWirte(neInfo model.NeInfo, filePath, content string, sync bool) error { +func (r *NeInfoImpl) NeConfigFileWirte(neInfo model.NeInfo, filePath, fileType string, content any, sync bool) error { neTypeLower := strings.ToLower(neInfo.NeType) // 网管本地路径 @@ -412,7 +440,13 @@ func (r *NeInfoImpl) NeConfigFileWirte(neInfo model.NeInfo, filePath, content st } localFilePath := fmt.Sprintf("%s/%s/%s/%s", omcPath, neTypeLower, neInfo.NeId, filePath) - err := os.WriteFile(localFilePath, []byte(content), 0644) + var err error + if fileType == "" || fileType == "txt" { + err = parse.ConvertConfigToFile(fileType, localFilePath, content) + } + if fileType == "json" || fileType == "yaml" || fileType == "yml" { + err = parse.ConvertConfigToFile(fileType, localFilePath, content) + } if err != nil { logger.Warnf("NeConfigFile WriteFile => %s", err.Error()) return fmt.Errorf("please check if the file exists or write permissions")