package controller import ( "fmt" "os" "path/filepath" "runtime" "strings" "github.com/gin-gonic/gin" "be.ems/src/framework/cmd" "be.ems/src/framework/i18n" "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/generate" neService "be.ems/src/modules/network_element/service" ) // 实例化控制层 NeActionController 结构体 var NewNeAction = &NeActionController{ neInfoService: neService.NewNeInfo, } // 网元处理请求 // // PATH /action type NeActionController struct { // 网元信息服务 neInfoService *neService.NeInfo } // 从本地到网元发送文件 // // POST /pushFile // // @Tags network_element/action // @Accept json // @Produce json // @Param data body object true "Request Param" // @Success 200 {object} object "Response Results" // @Security TokenAuth // @Summary Sending files from local to network elements // @Description Sending files from local to network elements // @Router /ne/action/pushFile [post] func (s *NeActionController) PushFile(c *gin.Context) { language := reqctx.AcceptLanguage(c) var body struct { NeType string `json:"neType" binding:"required"` NeID string `json:"neId" binding:"required"` UploadPath string `json:"uploadPath" binding:"required"` DelTemp bool `json:"delTemp"` // 删除本地临时文件 } if err := c.ShouldBindBodyWithJSON(&body); err != nil { errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) return } // 查询网元获取IP neInfo := s.neInfoService.FindByNeTypeAndNeID(body.NeType, body.NeID) if neInfo.NeId != body.NeID || neInfo.IP == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } // 网元主机的SSH客户端 // sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) // if err != nil { // c.JSON(200, resp.ErrMsg(err.Error())) // return // } // defer sshClient.Close() // // 网元主机的SSH客户端进行文件传输 // sftpClient, err := sshClient.NewClientSFTP() // if err != nil { // c.JSON(200, resp.ErrMsg(err.Error())) // return // } // defer sftpClient.Close() // 本地文件 localFilePath := file.ParseUploadFileAbsPath(body.UploadPath) // 网元端临时目录 // sshClient.RunCMD("mkdir -p /tmp/omc/push && sudo chmod 777 -R /tmp/omc") cmd.Exec("sudo mkdir -p /tmp/omc/push && sudo chmod 777 -R /tmp/omc") neFilePath := filepath.ToSlash(filepath.Join("/tmp/omc/push", filepath.Base(localFilePath))) // 复制到远程 // if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil { // c.JSON(200, resp.ErrMsg("Please check if the file exists or if scp is allowed to copy remotely")) // return // } if err := file.CopyFile(localFilePath, neFilePath); err != nil { c.JSON(200, resp.ErrMsg("Please check if the file exists or if scp is allowed to copy remotely")) return } defer func() { if body.DelTemp { _ = os.Remove(localFilePath) } }() c.JSON(200, resp.OkData(filepath.ToSlash(neFilePath))) } // 从网元到本地获取文件 // // GET /pullFile // // @Tags network_element/action // @Accept json // @Produce json // @Param neType query string true "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC) default(UPF) // @Param neId query string true "NE ID" default(001) // @Param path query string true "dir path" default(/var/log) // @Param fileName query string true "file name" // @Param delTemp query boolean false "Delete Temp File" default(false) // @Success 200 {object} object "Response Results" // @Security TokenAuth // @Summary Getting files from the network element to the local // @Description Getting files from the network element to the local // @Router /ne/action/pullFile [get] func (s *NeActionController) PullFile(c *gin.Context) { language := reqctx.AcceptLanguage(c) var querys struct { NeType string `form:"neType" binding:"required"` NeID string `form:"neId" binding:"required"` Path string `form:"path" binding:"required"` FileName string `form:"fileName" binding:"required"` DelTemp bool `form:"delTemp"` // 删除本地临时文件 } if err := c.ShouldBindQuery(&querys); err != nil { errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) return } // 查询网元获取IP neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) if neInfo.NeId != querys.NeID || neInfo.IP == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } // 网元主机的SSH客户端 // sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) // if err != nil { // c.JSON(200, resp.ErrMsg(err.Error())) // return // } // defer sshClient.Close() // // 网元主机的SSH客户端进行文件传输 // sftpClient, err := sshClient.NewClientSFTP() // if err != nil { // c.JSON(200, resp.ErrMsg(err.Error())) // return // } // defer sftpClient.Close() nePath := filepath.ToSlash(filepath.Join(querys.Path, querys.FileName)) fileName := generate.Code(6) + "_" + querys.FileName localFilePath := filepath.Join("/tmp/omc/pull", fileName) if runtime.GOOS == "windows" { localFilePath = fmt.Sprintf("C:%s", localFilePath) } // 复制到本地 // if err = sftpClient.CopyFileRemoteToLocal(nePath, localFilePath); err != nil { // c.JSON(200, resp.ErrMsg(err.Error())) // return // } if err := file.CopyFile(nePath, localFilePath); err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return } defer func() { if querys.DelTemp { _ = os.Remove(localFilePath) } }() c.FileAttachment(localFilePath, fileName) } // 从网元到本地获取目录压缩为ZIP // // GET /pullDirZip // // @Tags network_element/action // @Accept json // @Produce json // @Param neType query string true "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC) default(UPF) // @Param neId query string true "NE ID" default(001) // @Param path query string true "dir path" default(/var/log) // @Param delTemp query boolean false "Delete Temp File" default(false) // @Success 200 {object} object "Response Results" // @Security TokenAuth // @Summary Get directories compressed to ZIP from the network element to the local area // @Description Get directories compressed to ZIP from the network element to the local area // @Router /ne/action/pullDirZip [get] func (s *NeActionController) PullDirZip(c *gin.Context) { language := reqctx.AcceptLanguage(c) var querys struct { NeType string `form:"neType" binding:"required"` NeID string `form:"neId" binding:"required"` Path string `form:"path" binding:"required"` DelTemp bool `form:"delTemp"` // 删除本地临时文件 } if err := c.ShouldBindQuery(&querys); err != nil { errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) return } // 查询网元获取IP neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) if neInfo.NeId != querys.NeID || neInfo.IP == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } // 网元主机的SSH客户端 // sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) // if err != nil { // c.JSON(200, resp.ErrMsg(err.Error())) // return // } // defer sshClient.Close() // // 网元主机的SSH客户端进行文件传输 // sftpClient, err := sshClient.NewClientSFTP() // if err != nil { // c.JSON(200, resp.ErrMsg(err.Error())) // return // } // defer sftpClient.Close() nePath := querys.Path dirName := generate.Code(6) localFilePath := filepath.Join("/tmp/omc/pull/", dirName) if runtime.GOOS == "windows" { localFilePath = fmt.Sprintf("C:%s", localFilePath) } // 复制到本地 localDirFilePath := filepath.Join(localFilePath, "zip") // if err = sftpClient.CopyDirRemoteToLocal(nePath, localDirFilePath); err != nil { // c.JSON(200, resp.ErrMsg(err.Error())) // return // } if err := file.CopyDir(nePath, localDirFilePath); err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return } // 压缩zip文件名 zipFileName := fmt.Sprintf("%s-%s-%s.zip", neInfo.NeType, neInfo.NeId, dirName) zipFilePath := filepath.Join(localFilePath, zipFileName) if err := file.CompressZipByDir(zipFilePath, localDirFilePath); err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return } defer func() { if querys.DelTemp { _ = os.RemoveAll(localFilePath) } }() c.FileAttachment(zipFilePath, zipFileName) } // 查看网元端文件内容 // // GET /viewFile // // @Tags network_element/action // @Accept json // @Produce json // @Param neType query string true "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC) default(UPF) // @Param neId query string true "NE ID" default(001) // @Param path query string true "file path" default(/var/log) // @Param fileName query string true "file name" // @Success 200 {object} object "Response Results" // @Security TokenAuth // @Summary Viewing the contents of a file on the network element side // @Description Viewing the contents of a file on the network element side // @Router /ne/action/viewFile [get] func (s *NeActionController) ViewFile(c *gin.Context) { language := reqctx.AcceptLanguage(c) var querys struct { NeType string `form:"neType" binding:"required"` NeID string `form:"neId" binding:"required"` Path string `form:"path" binding:"required"` FileName string `form:"fileName" binding:"required"` } if err := c.ShouldBindQuery(&querys); err != nil { errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) return } // 查询网元获取IP neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) if neInfo.NeId != querys.NeID || neInfo.IP == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } // 网元主机的SSH客户端 // sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) // if err != nil { // c.JSON(200, resp.ErrMsg(err.Error())) // return // } // defer sshClient.Close() // 网元端文件 nePath := filepath.ToSlash(filepath.Join(querys.Path, querys.FileName)) // 网元端临时目录 output, err := cmd.Execf("cat %s", nePath) output = strings.TrimSpace(output) if err != nil || strings.HasPrefix(output, "ls: ") { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "file view cat error"))) return } c.JSON(200, resp.OkData(output)) } // 网元端文件列表 // // GET /files // // @Tags network_element/action // @Accept json // @Produce json // @Param neType query string true "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC) default(UPF) // @Param neId query string true "NE ID" default(001) // @Param path query string true "file path" default(/var/log) // @Param pageNum query number true "pageNum" default(1) // @Param pageSize query number true "pageSize" default(10) // @Param search query string false "search prefix" default(upf) // @Success 200 {object} object "Response Results" // @Security TokenAuth // @Summary List of files on the network element side // @Description List of files on the network element side // @Router /ne/action/files [get] func (s *NeActionController) Files(c *gin.Context) { var querys struct { NeType string `form:"neType" binding:"required"` NeID string `form:"neId" binding:"required"` Path string `form:"path" binding:"required"` PageNum int64 `form:"pageNum" binding:"required"` PageSize int64 `form:"pageSize" binding:"required"` Search string `form:"search"` } if err := c.ShouldBindQuery(&querys); err != nil { errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) return } // // 查询网元获取IP // neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) // if neInfo.NeId != querys.NeID || neInfo.IP == "" { // c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) // return // } // // 网元主机的SSH客户端 // sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) // if err != nil { // c.JSON(200, resp.ErrMsg(err.Error())) // return // } // defer sshClient.Close() // 获取文件列表 rows, err := file.FileList(querys.Path, querys.Search) if err != nil { c.JSON(200, resp.OkData(map[string]any{ "path": querys.Path, "total": len(rows), "rows": []file.FileListRow{}, })) return } // 对数组进行切片分页 lenNum := int64(len(rows)) start := (querys.PageNum - 1) * querys.PageSize end := start + querys.PageSize var splitRows []file.FileListRow if start >= lenNum { splitRows = []file.FileListRow{} } else if end >= lenNum { splitRows = rows[start:] } else { splitRows = rows[start:end] } c.JSON(200, resp.OkData(map[string]any{ "path": querys.Path, "total": lenNum, "rows": splitRows, })) } // 网元服务操作 // // PUT /service // // @Tags network_element/action // @Accept json // @Produce json // @Param data body object true "Request Param" // @Success 200 {object} object "Response Results" // @Security TokenAuth // @Summary Network element service operation // @Description Network element service operation // @Router /ne/action/service [put] func (s *NeActionController) Service(c *gin.Context) { language := reqctx.AcceptLanguage(c) var body struct { NeType string `json:"neType" binding:"required"` NeID string `json:"neId" binding:"required"` Action string `json:"action" binding:"required,oneof=start restart stop reboot poweroff"` // 操作行为 } if err := c.ShouldBindBodyWithJSON(&body); err != nil { errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) return } // 查询网元获取IP neInfo := s.neInfoService.FindByNeTypeAndNeID(body.NeType, body.NeID) if neInfo.NeId != body.NeID || neInfo.IP == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } neTypeLower := strings.ToLower(neInfo.NeType) cmdStr := fmt.Sprintf("sudo systemctl %s %s", body.Action, neTypeLower) if neTypeLower == "omc" { cmdStr = fmt.Sprintf("nohup sh -c \"sleep 5s && sudo systemctl %s omc\" > /dev/null 2>&1 &", body.Action) } else if neTypeLower == "ims" { if body.Action == "restart" { cmdStr = "ims-stop || true && ims-start" } else { cmdStr = fmt.Sprintf("sudo ims-%s", body.Action) } } if body.Action == "reboot" { cmdStr = "sudo shutdown -r now" } if body.Action == "poweroff" { cmdStr = "sudo shutdown -h now" } _, err := s.neInfoService.NeRunSSHCmd(body.NeType, body.NeID, cmdStr) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return } c.JSON(200, resp.Ok(nil)) }