Files
waf-platform/EdgeAPI/internal/installers/installer_node.go

173 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package installers
import (
"bytes"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"os"
"path/filepath"
"regexp"
)
type NodeInstaller struct {
BaseInstaller
}
func (this *NodeInstaller) Install(dir string, params interface{}, installStatus *models.NodeInstallStatus) error {
if params == nil {
return errors.New("'params' required for node installation")
}
nodeParams, ok := params.(*NodeParams)
if !ok {
return errors.New("'params' should be *NodeParams")
}
err := nodeParams.Validate()
if err != nil {
return fmt.Errorf("params validation: %w", err)
}
// 检查目标目录是否存在
_, err = this.client.Stat(dir)
if err != nil {
err = this.client.MkdirAll(dir)
if err != nil {
installStatus.ErrorCode = "CREATE_ROOT_DIRECTORY_FAILED"
return fmt.Errorf("create directory '%s' failed: %w", dir, err)
}
}
// 安装助手
env, err := this.InstallHelper(dir, nodeconfigs.NodeRoleNode)
if err != nil {
installStatus.ErrorCode = "INSTALL_HELPER_FAILED"
return err
}
// 上传安装文件
var filePrefix = "edge-node-" + env.OS + "-" + env.Arch
zipFile, err := this.LookupLatestInstallerForTarget(filePrefix, env)
if err != nil {
return err
}
if len(zipFile) == 0 {
return errors.New("can not find installer file for " + env.OS + "/" + env.Arch + ", expected '" + filePrefix + "-v*.zip' or distro-specific '" + filePrefix + "-{ubuntu22.04|amzn2023}-v*.zip'")
}
var targetZip = ""
var firstCopyErr error
var zipName = filepath.Base(zipFile)
for _, candidateTargetZip := range []string{
dir + "/" + zipName,
this.client.UserHome() + "/" + zipName,
"/tmp/" + zipName,
} {
err = this.client.Copy(zipFile, candidateTargetZip, 0777)
if err != nil {
if firstCopyErr == nil {
firstCopyErr = err
}
} else {
err = nil
firstCopyErr = nil
targetZip = candidateTargetZip
break
}
}
if firstCopyErr != nil {
return fmt.Errorf("upload node file failed: %w", firstCopyErr)
}
// 测试运行环境
// 升级的节点暂时不列入测试
if !nodeParams.IsUpgrading {
_, stderr, err := this.client.Exec(env.HelperPath + " -cmd=test")
if err != nil {
return fmt.Errorf("test failed: %w", err)
}
if len(stderr) > 0 {
return errors.New("test failed: " + stderr)
}
}
// 如果是升级则优雅停止先前的进程
var exePath = dir + "/edge-node/bin/edge-node"
if nodeParams.IsUpgrading {
_, err = this.client.Stat(exePath)
if err == nil {
_, _, _ = this.client.Exec(exePath + " quit")
// 删除可执行文件防止冲突
err = this.client.Remove(exePath)
if err != nil && err != os.ErrNotExist {
return fmt.Errorf("remove old file failed: %w", err)
}
}
}
// 解压
_, stderr, err := this.client.Exec(env.HelperPath + " -cmd=unzip -zip=\"" + targetZip + "\" -target=\"" + dir + "\"")
if err != nil {
return err
}
if len(stderr) > 0 {
return errors.New("unzip installer failed: " + stderr)
}
// 修改配置文件
{
var configFile = dir + "/edge-node/configs/api_node.yaml"
// sudo之后我们需要修改配置目录才能写入文件
if this.client.sudo {
_, _, _ = this.client.Exec("chown " + this.client.User() + " " + filepath.Dir(configFile))
}
var data = []byte(`rpc.endpoints: [ ${endpoints} ]
nodeId: "${nodeId}"
secret: "${nodeSecret}"`)
data = bytes.ReplaceAll(data, []byte("${endpoints}"), []byte(nodeParams.QuoteEndpoints()))
data = bytes.ReplaceAll(data, []byte("${nodeId}"), []byte(nodeParams.NodeId))
data = bytes.ReplaceAll(data, []byte("${nodeSecret}"), []byte(nodeParams.Secret))
_, err = this.client.WriteFile(configFile, data)
if err != nil {
return fmt.Errorf("write '%s': %w", configFile, err)
}
}
// 在线安装/更新 Fluent Bit与边缘节点安装流程联动
err = this.SetupFluentBit(nodeconfigs.NodeRoleNode)
if err != nil {
installStatus.ErrorCode = "SETUP_FLUENT_BIT_FAILED"
return fmt.Errorf("setup fluent-bit failed: %w", err)
}
// 测试
_, stderr, err = this.client.Exec(dir + "/edge-node/bin/edge-node test")
if err != nil {
installStatus.ErrorCode = "TEST_FAILED"
return fmt.Errorf("test edge node failed: %w, stderr: %s", err, stderr)
}
if len(stderr) > 0 {
if regexp.MustCompile(`(?i)rpc`).MatchString(stderr) {
installStatus.ErrorCode = "RPC_TEST_FAILED"
}
return errors.New("test edge node failed: " + stderr)
}
// 启动
_, stderr, err = this.client.Exec(dir + "/edge-node/bin/edge-node start")
if err != nil {
return fmt.Errorf("start edge node failed: %w", err)
}
if len(stderr) > 0 {
return errors.New("start edge node failed: " + stderr)
}
return nil
}