可以在集群中查看待安装节点、并直接安装节点

This commit is contained in:
GoEdgeLab
2020-10-26 21:14:56 +08:00
parent b286baf12e
commit 8444e9b312
11 changed files with 246 additions and 15 deletions

View File

@@ -60,7 +60,7 @@ function build() {
architects=("amd64" "386")
for arch in "${architects[@]}"; do
# TODO support arm, mips ...
env GOOS=linux GOARCH=${arch} go build --ldflags="-s -w" -o $ROOT/installers/installer-helper-linux-${arch} $ROOT/../cmd/installer-helper/main.go
env GOOS=linux GOARCH=${arch} go build --ldflags="-s -w" -o $ROOT/installers/edge-installer-helper-linux-${arch} $ROOT/../cmd/installer-helper/main.go
done
# building api node

View File

@@ -1 +1 @@
installer-*
edge-*

View File

@@ -171,6 +171,19 @@ func (this *APINodeDAO) FindAllEnabledAPINodes() (result []*APINode, err error)
return
}
// 列出所有可用而且启用的API节点
func (this *APINodeDAO) FindAllEnabledAndOnAPINodes() (result []*APINode, err error) {
_, err = this.Query().
Attr("clusterId", 0). // 非集群专用
Attr("isOn", true).
State(APINodeStateEnabled).
Desc("order").
AscPk().
Slice(&result).
FindAll()
return
}
// 计算API节点数量
func (this *APINodeDAO) CountAllEnabledAPINodes() (int64, error) {
return this.Query().

View File

@@ -268,6 +268,14 @@ func (this *NodeClusterDAO) FindAllEnabledClustersWithGrantId(grantId int64) (re
return
}
// 查找集群的认证ID
func (this *NodeClusterDAO) FindClusterGrantId(clusterId int64) (int64, error) {
return this.Query().
Pk(clusterId).
Result("grantId").
FindInt64Col(0)
}
// 生成唯一ID
func (this *NodeClusterDAO) genUniqueId() (string, error) {
for {

View File

@@ -376,21 +376,33 @@ func (this *NodeDAO) UpdateNodeIsInstalled(nodeId int64, isInstalled bool) error
// 查询节点的安装状态
func (this *NodeDAO) FindNodeInstallStatus(nodeId int64) (*NodeInstallStatus, error) {
installStatus, err := this.Query().
node, err := this.Query().
Pk(nodeId).
Result("installStatus").
FindStringCol("")
Result("installStatus", "isInstalled").
Find()
if err != nil {
return nil, err
}
if node == nil {
return nil, errors.New("not found")
}
installStatus := node.(*Node).InstallStatus
isInstalled := node.(*Node).IsInstalled == 1
if len(installStatus) == 0 {
return NewNodeInstallStatus(), nil
}
status := &NodeInstallStatus{}
err = json.Unmarshal([]byte(installStatus), status)
return status, err
if err != nil {
return nil, err
}
if isInstalled {
status.IsFinished = true
status.IsOk = true
}
return status, nil
}
// 修改节点的安装状态
@@ -524,6 +536,18 @@ func (this *NodeDAO) FindAllEnabledNodesWithGrantId(grantId int64) (result []*No
return
}
// 查找所有未安装的节点
func (this *NodeDAO) FindAllNotInstalledNodesWithClusterId(clusterId int64) (result []*Node, err error) {
_, err = this.Query().
State(NodeStateEnabled).
Attr("clusterId", clusterId).
Attr("isInstalled", false).
DescPk().
Slice(&result).
FindAll()
return
}
// 生成唯一ID
func (this *NodeDAO) genUniqueId() (string, error) {
for {

View File

@@ -6,6 +6,7 @@ type NodeInstallStatus struct {
IsFinished bool `json:"isFinished"` // 是否已结束
IsOk bool `json:"isOk"` // 是否正确安装
Error string `json:"error"` // 错误信息
ErrorCode string `json:"errorCode"` // 错误代号
UpdatedAt int64 `json:"updatedAt"` // 更新时间安装过程中需要每隔N秒钟更新这个状态以便于让系统知道安装仍在进行中
Steps []*NodeInstallStatusStep `json:"steps"` // 步骤
}

View File

@@ -0,0 +1,21 @@
package errors
type DetailedError struct {
msg string
code string
}
func (this *DetailedError) Error() string {
return this.msg
}
func (this *DetailedError) Code() string {
return this.code
}
func NewDetailedError(code string, error string) *DetailedError {
return &DetailedError{
msg: error,
code: code,
}
}

View File

@@ -151,12 +151,12 @@ func (this *BaseInstaller) InstallHelper(targetDir string) (env *Env, err error)
archName = "386"
}
exeName := "installer-helper-" + osName + "-" + archName
exeName := "edge-installer-helper-" + osName + "-" + archName
exePath := Tea.Root + "/installers/" + exeName
err = this.client.Copy(exePath, targetDir+"/"+exeName, 0777)
if err != nil {
return env, err
return env, errors.New("copy '" + exeName + "' to '" + targetDir + "' failed: " + err.Error())
}
env = &Env{

View File

@@ -23,6 +23,15 @@ func (this *NodeInstaller) Install(dir string, params interface{}) error {
return errors.New("params validation: " + err.Error())
}
// 检查目标目录是否存在
_, err = this.client.Stat(dir)
if err != nil {
err = this.client.MkdirAll(dir)
if err != nil {
return errors.New("create directory '" + dir + "' failed: " + err.Error())
}
}
// 安装助手
env, err := this.InstallHelper(dir)
if err != nil {

View File

@@ -5,8 +5,8 @@ import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/iwind/TeaGo/logs"
"strconv"
"time"
)
@@ -51,7 +51,7 @@ func (this *Queue) InstallNodeProcess(nodeId int64) error {
}()
// 开始安装
err = this.InstallNode(nodeId)
err = this.InstallNode(nodeId, installStatus)
// 安装结束
installStatus.IsRunning = false
@@ -78,13 +78,13 @@ func (this *Queue) InstallNodeProcess(nodeId int64) error {
}
// 安装边缘节点
func (this *Queue) InstallNode(nodeId int64) error {
func (this *Queue) InstallNode(nodeId int64, installStatus *models.NodeInstallStatus) error {
node, err := models.SharedNodeDAO.FindEnabledNode(nodeId)
if err != nil {
return err
}
if node == nil {
return errors.New("can not find node, ID'" + strconv.FormatInt(nodeId, 10) + "'")
return errors.New("can not find node, ID'" + numberutils.FormatInt64(nodeId) + "'")
}
// 登录信息
@@ -93,6 +93,7 @@ func (this *Queue) InstallNode(nodeId int64) error {
return err
}
if login == nil {
installStatus.ErrorCode = "EMPTY_LOGIN"
return errors.New("can not find node login information")
}
loginParams, err := login.DecodeSSHParams()
@@ -100,12 +101,35 @@ func (this *Queue) InstallNode(nodeId int64) error {
return err
}
if len(loginParams.Host) == 0 {
installStatus.ErrorCode = "EMPTY_SSH_HOST"
return errors.New("ssh host should not be empty")
}
if loginParams.Port <= 0 {
installStatus.ErrorCode = "EMPTY_SSH_PORT"
return errors.New("ssh port is invalid")
}
if loginParams.GrantId == 0 {
// 从集群中读取
grantId, err := models.SharedNodeClusterDAO.FindClusterGrantId(int64(node.ClusterId))
if err != nil {
return err
}
if grantId == 0 {
installStatus.ErrorCode = "EMPTY_GRANT"
return errors.New("can not find node grant")
}
loginParams.GrantId = grantId
}
grant, err := models.SharedNodeGrantDAO.FindEnabledNodeGrant(loginParams.GrantId)
if err != nil {
return err
}
if grant == nil {
return errors.New("can not find user grant with id '" + strconv.FormatInt(loginParams.GrantId, 10) + "'")
installStatus.ErrorCode = "EMPTY_GRANT"
return errors.New("can not find user grant with id '" + numberutils.FormatInt64(loginParams.GrantId) + "'")
}
// 安装目录
@@ -121,12 +145,13 @@ func (this *Queue) InstallNode(nodeId int64) error {
}
installDir = cluster.InstallDir
if len(installDir) == 0 {
return errors.New("unable to find installation dir")
// 默认是 $登录用户/edge-node
installDir = "/" + grant.Username + "/edge-node"
}
}
// API终端
apiNodes, err := models.SharedAPINodeDAO.FindAllEnabledAPINodes()
apiNodes, err := models.SharedAPINodeDAO.FindAllEnabledAndOnAPINodes()
if err != nil {
return err
}

View File

@@ -139,6 +139,7 @@ func (this *NodeService) ListEnabledNodesMatch(ctx context.Context, req *pb.List
IsFinished: installStatus.IsFinished,
IsOk: installStatus.IsOk,
Error: installStatus.Error,
ErrorCode: installStatus.ErrorCode,
UpdatedAt: installStatus.UpdatedAt,
}
}
@@ -295,6 +296,7 @@ func (this *NodeService) FindEnabledNode(ctx context.Context, req *pb.FindEnable
IsFinished: installStatus.IsFinished,
IsOk: installStatus.IsOk,
Error: installStatus.Error,
ErrorCode: installStatus.ErrorCode,
UpdatedAt: installStatus.UpdatedAt,
}
}
@@ -481,3 +483,131 @@ func (this *NodeService) FindAllEnabledNodesWithGrantId(ctx context.Context, req
return &pb.FindAllEnabledNodesWithGrantIdResponse{Nodes: result}, nil
}
// 列出所有未安装的节点
func (this *NodeService) FindAllNotInstalledNodesWithClusterId(ctx context.Context, req *pb.FindAllNotInstalledNodesWithClusterIdRequest) (*pb.FindAllNotInstalledNodesWithClusterIdResponse, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
nodes, err := models.SharedNodeDAO.FindAllNotInstalledNodesWithClusterId(req.ClusterId)
if err != nil {
return nil, err
}
result := []*pb.Node{}
for _, node := range nodes {
// 认证信息
login, err := models.SharedNodeLoginDAO.FindEnabledNodeLoginWithNodeId(int64(node.Id))
if err != nil {
return nil, err
}
var pbLogin *pb.NodeLogin = nil
if login != nil {
pbLogin = &pb.NodeLogin{
Id: int64(login.Id),
Name: login.Name,
Type: login.Type,
Params: []byte(login.Params),
}
}
// IP信息
addresses, err := models.SharedNodeIPAddressDAO.FindAllEnabledAddressesWithNode(int64(node.Id))
if err != nil {
return nil, err
}
pbAddresses := []*pb.NodeIPAddress{}
for _, address := range addresses {
pbAddresses = append(pbAddresses, &pb.NodeIPAddress{
Id: int64(address.Id),
NodeId: int64(address.NodeId),
Name: address.Name,
Ip: address.Ip,
Description: address.Description,
State: int64(address.State),
Order: int64(address.Order),
CanAccess: address.CanAccess == 1,
})
}
// 安装信息
installStatus, err := node.DecodeInstallStatus()
if err != nil {
return nil, err
}
pbInstallStatus := &pb.NodeInstallStatus{}
if installStatus != nil {
pbInstallStatus = &pb.NodeInstallStatus{
IsRunning: installStatus.IsRunning,
IsFinished: installStatus.IsFinished,
IsOk: installStatus.IsOk,
Error: installStatus.Error,
ErrorCode: installStatus.ErrorCode,
UpdatedAt: installStatus.UpdatedAt,
}
}
result = append(result, &pb.Node{
Id: int64(node.Id),
Name: node.Name,
Version: int64(node.Version),
IsInstalled: node.IsInstalled == 1,
Status: node.Status,
IsOn: node.IsOn == 1,
Login: pbLogin,
IpAddresses: pbAddresses,
InstallStatus: pbInstallStatus,
})
}
return &pb.FindAllNotInstalledNodesWithClusterIdResponse{Nodes: result}, nil
}
// 读取节点安装状态
func (this *NodeService) FindNodeInstallStatus(ctx context.Context, req *pb.FindNodeInstallStatusRequest) (*pb.FindNodeInstallStatusResponse, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
installStatus, err := models.SharedNodeDAO.FindNodeInstallStatus(req.NodeId)
if err != nil {
return nil, err
}
if installStatus == nil {
return &pb.FindNodeInstallStatusResponse{InstallStatus: nil}, nil
}
pbInstallStatus := &pb.NodeInstallStatus{
IsRunning: installStatus.IsRunning,
IsFinished: installStatus.IsFinished,
IsOk: installStatus.IsOk,
Error: installStatus.Error,
ErrorCode: installStatus.ErrorCode,
UpdatedAt: installStatus.UpdatedAt,
}
return &pb.FindNodeInstallStatusResponse{InstallStatus: pbInstallStatus}, nil
}
// 修改节点登录信息
func (this *NodeService) UpdateNodeLogin(ctx context.Context, req *pb.UpdateNodeLoginRequest) (*pb.RPCUpdateSuccess, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
if req.Login.Id <= 0 {
_, err := models.SharedNodeLoginDAO.CreateNodeLogin(req.NodeId, req.Login.Name, req.Login.Type, req.Login.Params)
if err != nil {
return nil, err
}
}
err = models.SharedNodeLoginDAO.UpdateNodeLogin(req.Login.Id, req.Login.Name, req.Login.Type, req.Login.Params)
return rpcutils.RPCUpdateSuccess()
}