mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 07:50:25 +08:00 
			
		
		
		
	远程升级API节点时自动上传边缘节点安装文件
This commit is contained in:
		@@ -5,6 +5,7 @@ import (
 | 
			
		||||
	"github.com/iwind/TeaGo/files"
 | 
			
		||||
	stringutil "github.com/iwind/TeaGo/utils/string"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var SharedDeployManager = NewDeployManager()
 | 
			
		||||
@@ -13,8 +14,11 @@ var SharedDeployManager = NewDeployManager()
 | 
			
		||||
// 如果节点部署文件有变化,需要重启API节点以便于生效
 | 
			
		||||
type DeployManager struct {
 | 
			
		||||
	dir string
 | 
			
		||||
 | 
			
		||||
	nodeFiles   []*DeployFile
 | 
			
		||||
	nsNodeFiles []*DeployFile
 | 
			
		||||
 | 
			
		||||
	locker sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewDeployManager 获取新节点部署文件管理器
 | 
			
		||||
@@ -29,24 +33,27 @@ func NewDeployManager() *DeployManager {
 | 
			
		||||
 | 
			
		||||
// LoadNodeFiles 加载所有边缘节点文件
 | 
			
		||||
func (this *DeployManager) LoadNodeFiles() []*DeployFile {
 | 
			
		||||
	this.locker.Lock()
 | 
			
		||||
	defer this.locker.Unlock()
 | 
			
		||||
 | 
			
		||||
	if len(this.nodeFiles) > 0 {
 | 
			
		||||
		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() {
 | 
			
		||||
		name := file.Name()
 | 
			
		||||
		var name = file.Name()
 | 
			
		||||
		if !reg.MatchString(name) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		matches := reg.FindStringSubmatch(name)
 | 
			
		||||
		osName := matches[1]
 | 
			
		||||
		arch := matches[2]
 | 
			
		||||
		version := matches[3]
 | 
			
		||||
		var matches = reg.FindStringSubmatch(name)
 | 
			
		||||
		var osName = matches[1]
 | 
			
		||||
		var arch = matches[2]
 | 
			
		||||
		var version = matches[3]
 | 
			
		||||
 | 
			
		||||
		key := osName + "_" + arch
 | 
			
		||||
		var key = osName + "_" + arch
 | 
			
		||||
		oldFile, ok := keyMap[key]
 | 
			
		||||
		if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
 | 
			
		||||
			continue
 | 
			
		||||
@@ -59,7 +66,7 @@ func (this *DeployManager) LoadNodeFiles() []*DeployFile {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result := []*DeployFile{}
 | 
			
		||||
	var result = []*DeployFile{}
 | 
			
		||||
	for _, v := range keyMap {
 | 
			
		||||
		result = append(result, v)
 | 
			
		||||
	}
 | 
			
		||||
@@ -81,24 +88,27 @@ func (this *DeployManager) FindNodeFile(os string, arch string) *DeployFile {
 | 
			
		||||
 | 
			
		||||
// LoadNSNodeFiles 加载所有NS节点安装文件
 | 
			
		||||
func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
 | 
			
		||||
	this.locker.Lock()
 | 
			
		||||
	defer this.locker.Unlock()
 | 
			
		||||
 | 
			
		||||
	if len(this.nsNodeFiles) > 0 {
 | 
			
		||||
		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() {
 | 
			
		||||
		name := file.Name()
 | 
			
		||||
		var name = file.Name()
 | 
			
		||||
		if !reg.MatchString(name) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		matches := reg.FindStringSubmatch(name)
 | 
			
		||||
		osName := matches[1]
 | 
			
		||||
		arch := matches[2]
 | 
			
		||||
		version := matches[3]
 | 
			
		||||
		var matches = reg.FindStringSubmatch(name)
 | 
			
		||||
		var osName = matches[1]
 | 
			
		||||
		var arch = matches[2]
 | 
			
		||||
		var version = matches[3]
 | 
			
		||||
 | 
			
		||||
		key := osName + "_" + arch
 | 
			
		||||
		var key = osName + "_" + arch
 | 
			
		||||
		oldFile, ok := keyMap[key]
 | 
			
		||||
		if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 {
 | 
			
		||||
			continue
 | 
			
		||||
@@ -111,7 +121,7 @@ func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result := []*DeployFile{}
 | 
			
		||||
	var result = []*DeployFile{}
 | 
			
		||||
	for _, v := range keyMap {
 | 
			
		||||
		result = append(result, v)
 | 
			
		||||
	}
 | 
			
		||||
@@ -130,3 +140,12 @@ func (this *DeployManager) FindNSNodeFile(os string, arch string) *DeployFile {
 | 
			
		||||
	}
 | 
			
		||||
	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"
 | 
			
		||||
	teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/db/models"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/installers"
 | 
			
		||||
	rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
 | 
			
		||||
	executils "github.com/TeaOSLab/EdgeAPI/internal/utils/exec"
 | 
			
		||||
	"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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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