feat: 统一备份数据发送ftp配置功能接口

This commit is contained in:
TsMask
2025-04-25 15:39:33 +08:00
parent 4d4f6095f6
commit eaf95cadf2
6 changed files with 217 additions and 147 deletions

View File

@@ -0,0 +1,101 @@
package controller
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/modules/network_data/model"
"be.ems/src/modules/network_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 BackupController 结构体
var NewBackup = &BackupController{
backupService: service.NewBackup,
}
// 备份数据
//
// PATH /backup
type BackupController struct {
backupService *service.Backup // 备份相关服务
}
// 备份文件-更新FTP配置
//
// PUT /ftp
func (s BackupController) FTPUpdate(c *gin.Context) {
var body model.BackupDataFTP
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(40422, errMsgs))
return
}
byteData, err := json.Marshal(body)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
up := s.backupService.FTPConfigUpdate(string(byteData), reqctx.LoginUserToUserName(c))
if up <= 0 {
c.JSON(200, resp.ErrMsg("update failed"))
return
}
c.JSON(200, resp.Ok(nil))
}
// 备份文件-获取FTP配置
//
// GET /ftp
func (s BackupController) FTPInfo(c *gin.Context) {
info := s.backupService.FTPConfigInfo()
c.JSON(200, resp.OkData(info))
}
// 备份文件-文件FTP发送
//
// POST /ftp
func (s BackupController) FTPPush(c *gin.Context) {
var body struct {
Path string `form:"path" binding:"required"` // 路径必须是 BACKUP_DIR 开头的路径
Filename string `form:"fileName" binding:"required"`
Tag string `form:"tag" binding:"required"` // 标签,用于区分不同的备份文件
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(40422, errMsgs))
return
}
// 判断路径是否合法
if !strings.HasPrefix(body.Path, s.backupService.BACKUP_DIR) {
c.JSON(200, resp.ErrMsg("operation path is not within the allowed range"))
return
}
// 判断文件是否存在
localFilePath := filepath.Join(body.Path, body.Filename)
if runtime.GOOS == "windows" {
localFilePath = fmt.Sprintf("C:%s", localFilePath)
}
if _, err := os.Stat(localFilePath); os.IsNotExist(err) {
c.JSON(200, resp.ErrMsg("file does not exist"))
return
}
// 发送文件
err := s.backupService.FTPPushFile(localFilePath, body.Tag)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}

View File

@@ -0,0 +1,11 @@
package model
// BackupDataFTP 备份数据FTP服务参数结构体
type BackupDataFTP struct {
Password string `json:"password"` // FTP密码
Username string `json:"username" binding:"required"` // FTP用户名
ToIp string `json:"toIp" binding:"required"` // FTP服务器IP
ToPort int64 `json:"toPort" binding:"required"` // FTP服务器端口
Dir string `json:"dir" binding:"required"` // FTP服务器目录
Enable bool `json:"enable"` // 是否启用
}

View File

@@ -206,6 +206,25 @@ func Setup(router *gin.Engine) {
)
}
// 备份数据
backupGroup := neDataGroup.Group("/backup")
{
backupGroup.GET("/ftp",
middleware.PreAuthorize(nil),
controller.NewBackup.FTPInfo,
)
backupGroup.PUT("/ftp",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.backup", collectlogs.BUSINESS_TYPE_OTHER)),
controller.NewBackup.FTPUpdate,
)
backupGroup.POST("/ftp",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.backup", collectlogs.BUSINESS_TYPE_OTHER)),
controller.NewBackup.FTPPush,
)
}
// 网元UDM 鉴权用户信息
udmAuthGroup := neDataGroup.Group("/udm/auth")
{

View File

@@ -0,0 +1,86 @@
package service
import (
"encoding/json"
"fmt"
"path/filepath"
"strings"
"be.ems/src/framework/ssh"
"be.ems/src/modules/network_data/model"
neService "be.ems/src/modules/network_element/service"
systemService "be.ems/src/modules/system/service"
)
// 实例化数据层 Backup 结构体
var NewBackup = &Backup{
BACKUP_DIR: "/usr/local/omc/backup",
neInfoService: neService.NewNeInfo,
sysConfigService: systemService.NewSysConfig,
}
// Backup 备份相关 服务层处理
type Backup struct {
BACKUP_DIR string // 备份目录
neInfoService *neService.NeInfo // 网元信息服务
sysConfigService *systemService.SysConfig // 参数配置服务
}
// FTPConfigUpdate 更新FTP配置信息
func (r Backup) FTPConfigUpdate(value, updateBy string) int64 {
cfg := r.sysConfigService.FindByKey("neData.backupDataFTP")
if cfg.ConfigId == 0 {
return 0
}
cfg.ConfigValue = value
cfg.UpdateBy = updateBy
return r.sysConfigService.UpdateEncryptValue(cfg)
}
// FTPConfigInfo 获取FTP配置信息
func (r Backup) FTPConfigInfo() model.BackupDataFTP {
info := model.BackupDataFTP{}
// 获取配置
cfg := r.sysConfigService.FindByKeyDecryptValue("neData.backupDataFTP")
if cfg.ConfigId > 0 && cfg.ConfigValue != "" {
if err := json.Unmarshal([]byte(cfg.ConfigValue), &info); err != nil {
return info
}
}
return info
}
// FTPPushFile 推送文件到FTP
func (r Backup) FTPPushFile(localFilePath, tag string) error {
cfgData := r.FTPConfigInfo()
if !cfgData.Enable {
return fmt.Errorf("setting remote backup ftp is disabled")
}
connSSH := ssh.ConnSSH{
User: cfgData.Username,
Password: cfgData.Password,
Addr: cfgData.ToIp,
Port: cfgData.ToPort,
AuthMode: "0",
}
sshClient, err := connSSH.NewClient()
if err != nil {
return err
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
return err
}
defer sftpClient.Close()
remotePath := strings.Replace(localFilePath, r.BACKUP_DIR, tag, 1)
remotePath = filepath.Join(cfgData.Dir, remotePath)
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, remotePath); err != nil {
return fmt.Errorf("error uploading file")
}
return nil
}