mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-06 10:00:24 +08:00
远程升级API节点时自动上传边缘节点安装文件
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/files"
|
"github.com/iwind/TeaGo/files"
|
||||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var SharedDeployManager = NewDeployManager()
|
var SharedDeployManager = NewDeployManager()
|
||||||
@@ -13,8 +14,11 @@ var SharedDeployManager = NewDeployManager()
|
|||||||
// 如果节点部署文件有变化,需要重启API节点以便于生效
|
// 如果节点部署文件有变化,需要重启API节点以便于生效
|
||||||
type DeployManager struct {
|
type DeployManager struct {
|
||||||
dir string
|
dir string
|
||||||
|
|
||||||
nodeFiles []*DeployFile
|
nodeFiles []*DeployFile
|
||||||
nsNodeFiles []*DeployFile
|
nsNodeFiles []*DeployFile
|
||||||
|
|
||||||
|
locker sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDeployManager 获取新节点部署文件管理器
|
// NewDeployManager 获取新节点部署文件管理器
|
||||||
@@ -29,24 +33,27 @@ func NewDeployManager() *DeployManager {
|
|||||||
|
|
||||||
// LoadNodeFiles 加载所有边缘节点文件
|
// LoadNodeFiles 加载所有边缘节点文件
|
||||||
func (this *DeployManager) LoadNodeFiles() []*DeployFile {
|
func (this *DeployManager) LoadNodeFiles() []*DeployFile {
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
if len(this.nodeFiles) > 0 {
|
if len(this.nodeFiles) > 0 {
|
||||||
return this.nodeFiles
|
return this.nodeFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
keyMap := map[string]*DeployFile{} // key => File
|
var keyMap = map[string]*DeployFile{} // key => File
|
||||||
|
|
||||||
reg := regexp.MustCompile(`^edge-node-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
|
var reg = regexp.MustCompile(`^edge-node-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
|
||||||
for _, file := range files.NewFile(this.dir).List() {
|
for _, file := range files.NewFile(this.dir).List() {
|
||||||
name := file.Name()
|
var name = file.Name()
|
||||||
if !reg.MatchString(name) {
|
if !reg.MatchString(name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
matches := reg.FindStringSubmatch(name)
|
var matches = reg.FindStringSubmatch(name)
|
||||||
osName := matches[1]
|
var osName = matches[1]
|
||||||
arch := matches[2]
|
var arch = matches[2]
|
||||||
version := matches[3]
|
var version = matches[3]
|
||||||
|
|
||||||
key := osName + "_" + arch
|
var key = osName + "_" + arch
|
||||||
oldFile, ok := keyMap[key]
|
oldFile, ok := keyMap[key]
|
||||||
if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
|
if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
|
||||||
continue
|
continue
|
||||||
@@ -59,7 +66,7 @@ func (this *DeployManager) LoadNodeFiles() []*DeployFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result := []*DeployFile{}
|
var result = []*DeployFile{}
|
||||||
for _, v := range keyMap {
|
for _, v := range keyMap {
|
||||||
result = append(result, v)
|
result = append(result, v)
|
||||||
}
|
}
|
||||||
@@ -81,24 +88,27 @@ func (this *DeployManager) FindNodeFile(os string, arch string) *DeployFile {
|
|||||||
|
|
||||||
// LoadNSNodeFiles 加载所有NS节点安装文件
|
// LoadNSNodeFiles 加载所有NS节点安装文件
|
||||||
func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
|
func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
if len(this.nsNodeFiles) > 0 {
|
if len(this.nsNodeFiles) > 0 {
|
||||||
return this.nsNodeFiles
|
return this.nsNodeFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
keyMap := map[string]*DeployFile{} // key => File
|
var keyMap = map[string]*DeployFile{} // key => File
|
||||||
|
|
||||||
reg := regexp.MustCompile(`^edge-dns-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
|
var reg = regexp.MustCompile(`^edge-dns-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
|
||||||
for _, file := range files.NewFile(this.dir).List() {
|
for _, file := range files.NewFile(this.dir).List() {
|
||||||
name := file.Name()
|
var name = file.Name()
|
||||||
if !reg.MatchString(name) {
|
if !reg.MatchString(name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
matches := reg.FindStringSubmatch(name)
|
var matches = reg.FindStringSubmatch(name)
|
||||||
osName := matches[1]
|
var osName = matches[1]
|
||||||
arch := matches[2]
|
var arch = matches[2]
|
||||||
version := matches[3]
|
var version = matches[3]
|
||||||
|
|
||||||
key := osName + "_" + arch
|
var key = osName + "_" + arch
|
||||||
oldFile, ok := keyMap[key]
|
oldFile, ok := keyMap[key]
|
||||||
if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
|
if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
|
||||||
continue
|
continue
|
||||||
@@ -111,7 +121,7 @@ func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result := []*DeployFile{}
|
var result = []*DeployFile{}
|
||||||
for _, v := range keyMap {
|
for _, v := range keyMap {
|
||||||
result = append(result, v)
|
result = append(result, v)
|
||||||
}
|
}
|
||||||
@@ -130,3 +140,12 @@ func (this *DeployManager) FindNSNodeFile(os string, arch string) *DeployFile {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reload 重置缓存
|
||||||
|
func (this *DeployManager) Reload() {
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
|
this.nodeFiles = nil
|
||||||
|
this.nsNodeFiles = nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/installers"
|
||||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||||
executils "github.com/TeaOSLab/EdgeAPI/internal/utils/exec"
|
executils "github.com/TeaOSLab/EdgeAPI/internal/utils/exec"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
@@ -481,3 +482,106 @@ func (this *APINodeService) UploadAPINodeFile(ctx context.Context, req *pb.Uploa
|
|||||||
|
|
||||||
return &pb.UploadAPINodeFileResponse{}, nil
|
return &pb.UploadAPINodeFileResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UploadDeployFileToAPINode 上传节点安装文件
|
||||||
|
func (this *APINodeService) UploadDeployFileToAPINode(ctx context.Context, req *pb.UploadDeployFileToAPINodeRequest) (*pb.RPCSuccess, error) {
|
||||||
|
_, err := this.ValidateAdmin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetDir = Tea.Root + "/deploy/"
|
||||||
|
var targetTmpFile = targetDir + "/" + req.Filename + ".tmp"
|
||||||
|
var targetFile = targetDir + "/" + req.Filename
|
||||||
|
|
||||||
|
if req.IsFirstChunk {
|
||||||
|
_ = os.Remove(targetTmpFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.ChunkData) > 0 {
|
||||||
|
err = func() error {
|
||||||
|
var flags = os.O_CREATE | os.O_WRONLY
|
||||||
|
if req.IsFirstChunk {
|
||||||
|
flags |= os.O_TRUNC
|
||||||
|
} else {
|
||||||
|
flags |= os.O_APPEND
|
||||||
|
}
|
||||||
|
fp, err := os.OpenFile(targetTmpFile, flags, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = fp.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = fp.Write(req.ChunkData)
|
||||||
|
return err
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("write file failed: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.IsLastChunk {
|
||||||
|
// 检查SUM
|
||||||
|
fp, err := os.Open(targetTmpFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var hash = md5.New()
|
||||||
|
_, err = io.Copy(hash, fp)
|
||||||
|
_ = fp.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var tmpSum = fmt.Sprintf("%x", hash.Sum(nil))
|
||||||
|
if tmpSum != req.Sum {
|
||||||
|
_ = os.Remove(targetTmpFile)
|
||||||
|
return nil, errors.New("check sum failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正式改名
|
||||||
|
err = os.Rename(targetTmpFile, targetFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("rename failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重载数据
|
||||||
|
installers.SharedDeployManager.Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Success()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindLatestDeployFiles 查找已有节点安装文件信息
|
||||||
|
func (this *APINodeService) FindLatestDeployFiles(ctx context.Context, req *pb.FindLatestDeployFilesRequest) (*pb.FindLatestDeployFilesResponse, error) {
|
||||||
|
_, err := this.ValidateAdmin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pbNodeFiles = []*pb.FindLatestDeployFilesResponse_DeployFile{}
|
||||||
|
var nodeFiles = installers.SharedDeployManager.LoadNodeFiles()
|
||||||
|
for _, nodeFile := range nodeFiles {
|
||||||
|
pbNodeFiles = append(pbNodeFiles, &pb.FindLatestDeployFilesResponse_DeployFile{
|
||||||
|
Os: nodeFile.OS,
|
||||||
|
Arch: nodeFile.Arch,
|
||||||
|
Version: nodeFile.Version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var pbNSNodeFiles = []*pb.FindLatestDeployFilesResponse_DeployFile{}
|
||||||
|
var nsNodeFiles = installers.SharedDeployManager.LoadNSNodeFiles()
|
||||||
|
for _, nodeFile := range nsNodeFiles {
|
||||||
|
pbNSNodeFiles = append(pbNSNodeFiles, &pb.FindLatestDeployFilesResponse_DeployFile{
|
||||||
|
Os: nodeFile.OS,
|
||||||
|
Arch: nodeFile.Arch,
|
||||||
|
Version: nodeFile.Version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.FindLatestDeployFilesResponse{
|
||||||
|
NodeDeployFiles: pbNodeFiles,
|
||||||
|
NsNodeDeployFiles: pbNSNodeFiles,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user