diff --git a/internal/utils/numberutils/utils.go b/internal/utils/numberutils/utils.go new file mode 100644 index 00000000..b7cd4b35 --- /dev/null +++ b/internal/utils/numberutils/utils.go @@ -0,0 +1,11 @@ +package numberutils + +import "strconv" + +func FormatInt64(value int64) string { + return strconv.FormatInt(value, 10) +} + +func FormatInt(value int) string { + return strconv.Itoa(value) +} diff --git a/internal/web/actions/default/clusters/cluster/createBatch.go b/internal/web/actions/default/clusters/cluster/createBatch.go new file mode 100644 index 00000000..aca4a1da --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/createBatch.go @@ -0,0 +1,98 @@ +package cluster + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/actions" + "github.com/iwind/TeaGo/lists" + "github.com/iwind/TeaGo/maps" + "net" + "strconv" + "strings" +) + +type CreateBatchAction struct { + actionutils.ParentAction +} + +func (this *CreateBatchAction) Init() { + this.Nav("", "node", "create") + this.SecondMenu("nodes") +} + +func (this *CreateBatchAction) RunGet(params struct { + ClusterId int64 +}) { + leftMenuItems := []maps.Map{ + { + "name": "单个创建", + "url": "/clusters/cluster/createNode?clusterId=" + strconv.FormatInt(params.ClusterId, 10), + "isActive": false, + }, + { + "name": "批量创建", + "url": "/clusters/cluster/createBatch?clusterId=" + strconv.FormatInt(params.ClusterId, 10), + "isActive": true, + }, + } + this.Data["leftMenuItems"] = leftMenuItems + + this.Show() +} + +func (this *CreateBatchAction) RunPost(params struct { + ClusterId int64 + IpList string + + Must *actions.Must +}) { + if params.ClusterId <= 0 { + this.Fail("请选择正确的集群") + } + + // 校验 + // TODO 支持IP范围,比如:192.168.1.[100-105] + realIPList := []string{} + for _, ip := range strings.Split(params.IpList, "\n") { + ip = strings.TrimSpace(ip) + if len(ip) == 0 { + continue + } + ip = strings.ReplaceAll(ip, " ", "") + + if net.ParseIP(ip) == nil { + this.Fail("发现错误的IP地址:" + ip) + } + + if lists.ContainsString(realIPList, ip) { + continue + } + realIPList = append(realIPList, ip) + } + + // 保存 + for _, ip := range realIPList { + resp, err := this.RPC().NodeRPC().CreateNode(this.AdminContext(), &pb.CreateNodeRequest{ + Name: ip, + ClusterId: params.ClusterId, + Login: nil, + }) + if err != nil { + this.ErrorPage(err) + return + } + nodeId := resp.NodeId + _, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{ + NodeId: nodeId, + Name: "IP地址", + Ip: ip, + CanAccess: true, + }) + if err != nil { + this.ErrorPage(err) + return + } + } + + this.Success() +} diff --git a/internal/web/actions/default/clusters/cluster/createNode.go b/internal/web/actions/default/clusters/cluster/createNode.go new file mode 100644 index 00000000..d83868db --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/createNode.go @@ -0,0 +1,120 @@ +package cluster + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/actions" + "github.com/iwind/TeaGo/maps" + "strconv" +) + +// 创建节点 +type CreateNodeAction struct { + actionutils.ParentAction +} + +func (this *CreateNodeAction) Init() { + this.Nav("", "node", "create") + this.SecondMenu("nodes") +} + +func (this *CreateNodeAction) RunGet(params struct { + ClusterId int64 +}) { + leftMenuItems := []maps.Map{ + { + "name": "单个创建", + "url": "/clusters/cluster/createNode?clusterId=" + strconv.FormatInt(params.ClusterId, 10), + "isActive": true, + }, + { + "name": "批量创建", + "url": "/clusters/cluster/createBatch?clusterId=" + strconv.FormatInt(params.ClusterId, 10), + "isActive": false, + }, + } + this.Data["leftMenuItems"] = leftMenuItems + + this.Show() +} + +func (this *CreateNodeAction) RunPost(params struct { + Name string + IpAddressesJSON []byte + ClusterId int64 + GrantId int64 + SshHost string + SshPort int + + Must *actions.Must +}) { + params.Must. + Field("name", params.Name). + Require("请输入节点名称") + + if len(params.IpAddressesJSON) == 0 { + this.Fail("请至少添加一个IP地址") + } + + // TODO 检查cluster + if params.ClusterId <= 0 { + this.Fail("请选择所在集群") + } + + // TODO 检查登录授权 + loginInfo := &pb.NodeLogin{ + Id: 0, + Name: "SSH", + Type: "ssh", + Params: maps.Map{ + "grantId": params.GrantId, + "host": params.SshHost, + "port": params.SshPort, + }.AsJSON(), + } + + // 保存 + createResp, err := this.RPC().NodeRPC().CreateNode(this.AdminContext(), &pb.CreateNodeRequest{ + Name: params.Name, + ClusterId: params.ClusterId, + Login: loginInfo, + }) + if err != nil { + this.ErrorPage(err) + return + } + nodeId := createResp.NodeId + + // IP地址 + ipAddresses := []maps.Map{} + if len(params.IpAddressesJSON) > 0 { + err = json.Unmarshal(params.IpAddressesJSON, &ipAddresses) + if err != nil { + this.ErrorPage(err) + return + } + for _, address := range ipAddresses { + addressId := address.GetInt64("id") + if addressId > 0 { + _, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{ + AddressId: addressId, + NodeId: nodeId, + }) + } else { + _, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{ + NodeId: nodeId, + Name: address.GetString("name"), + Ip: address.GetString("ip"), + CanAccess: address.GetBool("canAccess"), + }) + } + if err != nil { + this.ErrorPage(err) + return + } + } + } + + this.Success() +} diff --git a/internal/web/actions/default/clusters/cluster/init.go b/internal/web/actions/default/clusters/cluster/init.go index 975b4994..d7903342 100644 --- a/internal/web/actions/default/clusters/cluster/init.go +++ b/internal/web/actions/default/clusters/cluster/init.go @@ -15,11 +15,15 @@ func init() { Prefix("/clusters/cluster"). Get("", new(IndexAction)). GetPost("/installNodes", new(InstallNodesAction)). + GetPost("/installRemote", new(InstallRemoteAction)). + Post("/installStatus", new(InstallStatusAction)). GetPost("/delete", new(DeleteAction)). + GetPost("/createNode", new(CreateNodeAction)). + GetPost("/createBatch", new(CreateBatchAction)). + GetPost("/updateNodeSSH", new(UpdateNodeSSHAction)). // 节点相关 Get("/node", new(node.NodeAction)). - GetPost("/node/create", new(node.CreateAction)). GetPost("/node/update", new(node.UpdateAction)). GetPost("/node/install", new(node.InstallAction)). Post("/node/updateInstallStatus", new(node.UpdateInstallStatusAction)). diff --git a/internal/web/actions/default/clusters/cluster/installNodes.go b/internal/web/actions/default/clusters/cluster/installNodes.go index eb0f9642..c27d45a5 100644 --- a/internal/web/actions/default/clusters/cluster/installNodes.go +++ b/internal/web/actions/default/clusters/cluster/installNodes.go @@ -1,6 +1,7 @@ package cluster import ( + "github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/iwind/TeaGo/maps" @@ -19,6 +20,19 @@ func (this *InstallNodesAction) Init() { func (this *InstallNodesAction) RunGet(params struct { ClusterId int64 }) { + this.Data["leftMenuItems"] = []maps.Map{ + { + "name": "自动注册", + "url": "/clusters/cluster/installNodes?clusterId=" + numberutils.FormatInt64(params.ClusterId), + "isActive": true, + }, + { + "name": "远程安装", + "url": "/clusters/cluster/installRemote?clusterId=" + numberutils.FormatInt64(params.ClusterId), + "isActive": false, + }, + } + clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{ClusterId: params.ClusterId}) if err != nil { this.ErrorPage(err) diff --git a/internal/web/actions/default/clusters/cluster/installRemote.go b/internal/web/actions/default/clusters/cluster/installRemote.go new file mode 100644 index 00000000..4d22c2c2 --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/installRemote.go @@ -0,0 +1,94 @@ +package cluster + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/actions" + "github.com/iwind/TeaGo/maps" +) + +type InstallRemoteAction struct { + actionutils.ParentAction +} + +func (this *InstallRemoteAction) Init() { + this.Nav("", "node", "install") + this.SecondMenu("nodes") +} + +func (this *InstallRemoteAction) RunGet(params struct { + ClusterId int64 +}) { + this.Data["leftMenuItems"] = []maps.Map{ + { + "name": "自动注册", + "url": "/clusters/cluster/installNodes?clusterId=" + numberutils.FormatInt64(params.ClusterId), + "isActive": false, + }, + { + "name": "远程安装", + "url": "/clusters/cluster/installRemote?clusterId=" + numberutils.FormatInt64(params.ClusterId), + "isActive": true, + }, + } + + nodesResp, err := this.RPC().NodeRPC().FindAllNotInstalledNodesWithClusterId(this.AdminContext(), &pb.FindAllNotInstalledNodesWithClusterIdRequest{ClusterId: params.ClusterId}) + if err != nil { + this.ErrorPage(err) + return + } + + nodeMaps := []maps.Map{} + for _, node := range nodesResp.Nodes { + loginParams := maps.Map{} + if node.Login != nil && len(node.Login.Params) > 0 { + err := json.Unmarshal(node.Login.Params, &loginParams) + if err != nil { + this.ErrorPage(err) + return + } + } + + installStatus := maps.Map{ + "isRunning": false, + "isFinished": false, + } + if node.InstallStatus != nil { + installStatus = maps.Map{ + "isRunning": node.InstallStatus.IsRunning, + "isFinished": node.InstallStatus.IsFinished, + "isOk": node.InstallStatus.IsOk, + "error": node.InstallStatus.Error, + } + } + + nodeMaps = append(nodeMaps, maps.Map{ + "id": node.Id, + "isOn": node.IsOn, + "name": node.Name, + "addresses": node.IpAddresses, + "login": node.Login, + "loginParams": loginParams, + "installStatus": installStatus, + }) + } + this.Data["nodes"] = nodeMaps + + this.Show() +} + +func (this *InstallRemoteAction) RunPost(params struct { + NodeId int64 + + Must *actions.Must +}) { + _, err := this.RPC().NodeRPC().InstallNode(this.AdminContext(), &pb.InstallNodeRequest{NodeId: params.NodeId}) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/clusters/cluster/installStatus.go b/internal/web/actions/default/clusters/cluster/installStatus.go new file mode 100644 index 00000000..f376c99b --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/installStatus.go @@ -0,0 +1,35 @@ +package cluster + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) + +type InstallStatusAction struct { + actionutils.ParentAction +} + +func (this *InstallStatusAction) RunPost(params struct { + NodeId int64 +}) { + resp, err := this.RPC().NodeRPC().FindNodeInstallStatus(this.AdminContext(), &pb.FindNodeInstallStatusRequest{NodeId: params.NodeId}) + if err != nil { + this.ErrorPage(err) + return + } + if resp.InstallStatus == nil { + this.Data["status"] = nil + this.Success() + } + + this.Data["status"] = maps.Map{ + "isRunning": resp.InstallStatus.IsRunning, + "isFinished": resp.InstallStatus.IsFinished, + "isOk": resp.InstallStatus.IsOk, + "error": resp.InstallStatus.Error, + "errorCode": resp.InstallStatus.ErrorCode, + } + + this.Success() +} diff --git a/internal/web/actions/default/clusters/cluster/node/create.go b/internal/web/actions/default/clusters/cluster/node/create.go deleted file mode 100644 index 276f2a90..00000000 --- a/internal/web/actions/default/clusters/cluster/node/create.go +++ /dev/null @@ -1,88 +0,0 @@ -package node - -import ( - "encoding/json" - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" - "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" - "github.com/iwind/TeaGo/actions" - "github.com/iwind/TeaGo/maps" -) - -// 创建节点 -type CreateAction struct { - actionutils.ParentAction -} - -func (this *CreateAction) Init() { - this.Nav("", "node", "create") - this.SecondMenu("nodes") -} - -func (this *CreateAction) RunGet(params struct{}) { - this.Show() -} - -func (this *CreateAction) RunPost(params struct { - Name string - IPAddresses string `alias:"ipAddresses"` - ClusterId int64 - GrantId int64 - SshHost string - SshPort int - - Must *actions.Must -}) { - params.Must. - Field("name", params.Name). - Require("请输入节点名称") - - // TODO 检查cluster - if params.ClusterId <= 0 { - this.Fail("请选择所在集群") - } - - // TODO 检查登录授权 - loginInfo := &pb.NodeLogin{ - Id: 0, - Name: "SSH", - Type: "ssh", - Params: maps.Map{ - "grantId": params.GrantId, - "host": params.SshHost, - "port": params.SshPort, - }.AsJSON(), - } - - // 保存 - createResp, err := this.RPC().NodeRPC().CreateNode(this.AdminContext(), &pb.CreateNodeRequest{ - Name: params.Name, - ClusterId: params.ClusterId, - Login: loginInfo, - }) - if err != nil { - this.ErrorPage(err) - return - } - nodeId := createResp.NodeId - - // IP地址 - ipAddresses := []maps.Map{} - err = json.Unmarshal([]byte(params.IPAddresses), &ipAddresses) - if err != nil { - this.ErrorPage(err) - return - } - for _, address := range ipAddresses { - addressId := address.GetInt64("id") - _, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{ - AddressId: addressId, - NodeId: nodeId, - }) - if err != nil { - this.ErrorPage(err) - return - } - } - - this.Success() -} diff --git a/internal/web/actions/default/clusters/cluster/node/install.go b/internal/web/actions/default/clusters/cluster/node/install.go index ceee2c38..a0494d51 100644 --- a/internal/web/actions/default/clusters/cluster/node/install.go +++ b/internal/web/actions/default/clusters/cluster/node/install.go @@ -76,6 +76,9 @@ func (this *InstallAction) RunGet(params struct { apiNodes := apiNodesResp.Nodes apiEndpoints := []string{} for _, apiNode := range apiNodes { + if !apiNode.IsOn { + continue + } apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...) } this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\"" diff --git a/internal/web/actions/default/clusters/cluster/updateNodeSSH.go b/internal/web/actions/default/clusters/cluster/updateNodeSSH.go new file mode 100644 index 00000000..e43c1e2e --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/updateNodeSSH.go @@ -0,0 +1,119 @@ +package cluster + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/actions" + "github.com/iwind/TeaGo/maps" +) + +type UpdateNodeSSHAction struct { + actionutils.ParentAction +} + +func (this *UpdateNodeSSHAction) Init() { + this.Nav("", "", "") +} + +func (this *UpdateNodeSSHAction) RunGet(params struct { + NodeId int64 +}) { + nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId}) + if err != nil { + this.ErrorPage(err) + return + } + if nodeResp.Node == nil { + this.NotFound("node", params.NodeId) + return + } + + node := nodeResp.Node + this.Data["node"] = maps.Map{ + "id": node.Id, + "name": node.Name, + } + + // SSH + loginParams := maps.Map{ + "host": "", + "port": "", + "grantId": 0, + } + this.Data["loginId"] = 0 + if node.Login != nil { + this.Data["loginId"] = node.Login.Id + if len(node.Login.Params) > 0 { + err = json.Unmarshal(node.Login.Params, &loginParams) + if err != nil { + this.ErrorPage(err) + return + } + } + } + this.Data["params"] = loginParams + + // 认证信息 + grantId := loginParams.GetInt64("grantId") + grantResp, err := this.RPC().NodeGrantRPC().FindEnabledGrant(this.AdminContext(), &pb.FindEnabledGrantRequest{GrantId: grantId}) + if err != nil { + this.ErrorPage(err) + } + var grantMap maps.Map = nil + if grantResp.Grant != nil { + grantMap = maps.Map{ + "id": grantResp.Grant.Id, + "name": grantResp.Grant.Name, + "method": grantResp.Grant.Method, + "methodName": grantutils.FindGrantMethodName(grantResp.Grant.Method), + } + } + this.Data["grant"] = grantMap + + this.Show() +} + +func (this *UpdateNodeSSHAction) RunPost(params struct { + NodeId int64 + LoginId int64 + SshHost string + SshPort int + GrantId int64 + + Must *actions.Must +}) { + params.Must. + Field("sshHost", params.SshHost). + Require("请输入SSH主机地址"). + Field("sshPort", params.SshPort). + Gt(0, "SSH主机端口需要大于0"). + Lt(65535, "SSH主机端口需要小于65535") + + if params.GrantId <= 0 { + this.Fail("需要选择或填写至少一个认证信息") + } + + login := &pb.NodeLogin{ + Id: params.LoginId, + Name: "SSH", + Type: "ssh", + Params: maps.Map{ + "grantId": params.GrantId, + "host": params.SshHost, + "port": params.SshPort, + }.AsJSON(), + } + + _, err := this.RPC().NodeRPC().UpdateNodeLogin(this.AdminContext(), &pb.UpdateNodeLoginRequest{ + NodeId: params.NodeId, + Login: login, + }) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/clusters/clusterutils/cluster_helper.go b/internal/web/actions/default/clusters/clusterutils/cluster_helper.go index 34464a3d..e0af9612 100644 --- a/internal/web/actions/default/clusters/clusterutils/cluster_helper.go +++ b/internal/web/actions/default/clusters/clusterutils/cluster_helper.go @@ -36,47 +36,37 @@ func (this *ClusterHelper) BeforeAction(action *actions.ActionObject) { return } - clusterResp, err := rpcClient.NodeClusterRPC().FindEnabledNodeCluster(rpcClient.Context(action.Context.GetInt64("adminId")), &pb.FindEnabledNodeClusterRequest{ClusterId: clusterId}) - if err != nil { - logs.Error(err) - return - } - cluster := clusterResp.Cluster - if cluster == nil { - action.WriteString("can not find cluster") - return - } + if clusterId > 0 { + clusterResp, err := rpcClient.NodeClusterRPC().FindEnabledNodeCluster(rpcClient.Context(action.Context.GetInt64("adminId")), &pb.FindEnabledNodeClusterRequest{ClusterId: clusterId}) + if err != nil { + logs.Error(err) + return + } + cluster := clusterResp.Cluster + if cluster == nil { + action.WriteString("can not find cluster") + return + } - tabbar := actionutils.NewTabbar() - tabbar.Add("集群列表", "", "/clusters", "", false) - tabbar.Add("节点", "", "/clusters/cluster?clusterId="+clusterIdString, "server", selectedTabbar == "node") - tabbar.Add("设置", "", "/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting") - tabbar.Add("删除", "", "/clusters/cluster/delete?clusterId="+clusterIdString, "trash", selectedTabbar == "delete") + tabbar := actionutils.NewTabbar() + tabbar.Add("集群列表", "", "/clusters", "", false) + tabbar.Add("节点", "", "/clusters/cluster?clusterId="+clusterIdString, "server", selectedTabbar == "node") + tabbar.Add("设置", "", "/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting") + tabbar.Add("删除", "", "/clusters/cluster/delete?clusterId="+clusterIdString, "trash", selectedTabbar == "delete") - { - m := tabbar.Add("当前集群:"+cluster.Name, "", "/clusters/cluster?clusterId="+clusterIdString, "", false) - m["right"] = true + { + m := tabbar.Add("当前集群:"+cluster.Name, "", "/clusters/cluster?clusterId="+clusterIdString, "", false) + m["right"] = true + } + actionutils.SetTabbar(action, tabbar) + + // 左侧菜单 + secondMenuItem := action.Data.GetString("secondMenuItem") + switch selectedTabbar { + case "setting": + action.Data["leftMenuItems"] = this.createSettingMenu(clusterIdString, secondMenuItem) + } } - actionutils.SetTabbar(action, tabbar) - - // 左侧菜单 - secondMenuItem := action.Data.GetString("secondMenuItem") - switch selectedTabbar { - case "setting": - action.Data["leftMenuItems"] = this.createSettingMenu(clusterIdString, secondMenuItem) - case "node": - action.Data["leftMenuItems"] = this.createNodeMenu(clusterIdString, secondMenuItem) - } -} - -// 节点菜单 -func (this *ClusterHelper) createNodeMenu(clusterId string, selectedItem string) (items []maps.Map) { - items = append(items, maps.Map{ - "name": "节点列表", - "url": "/clusters/cluster?clusterId=" + clusterId, - "isActive": selectedItem == "nodes", - }) - return } // 设置菜单 diff --git a/web/public/js/components/common/health-check-config-box.js b/web/public/js/components/common/health-check-config-box.js index 775b2d95..48da937d 100644 --- a/web/public/js/components/common/health-check-config-box.js +++ b/web/public/js/components/common/health-check-config-box.js @@ -21,12 +21,28 @@ Vue.component("health-check-config-box", { that.changeURL() }, 500) } else { - let url = new URL(healthCheckConfig.url) - urlProtocol = url.protocol.substring(0, url.protocol.length - 1) - urlPort = url.port - urlRequestURI = url.pathname - if (url.search.length > 0) { - urlRequestURI += url.search + try { + let url = new URL(healthCheckConfig.url) + urlProtocol = url.protocol.substring(0, url.protocol.length - 1) + urlPort = url.port + urlRequestURI = url.pathname + if (url.search.length > 0) { + urlRequestURI += url.search + } + } catch (e) { + } + + if (healthCheckConfig.statusCodes == null) { + healthCheckConfig.statusCodes = [200] + } + if (healthCheckConfig.interval == null) { + healthCheckConfig.interval = {count: 60, unit: "second"} + } + if (healthCheckConfig.timeout == null) { + healthCheckConfig.timeout = {count: 10, unit: "second"} + } + if (healthCheckConfig.tryDelay == null) { + healthCheckConfig.tryDelay = {count: 100, unit: "ms"} } } return { @@ -81,7 +97,6 @@ Vue.component("health-check-config-box", { return status } }) - console.log(this.healthCheck.statusCodes) } }, template: `
diff --git a/web/public/js/components/common/values-box.js b/web/public/js/components/common/values-box.js index 0262305d..d48d9541 100644 --- a/web/public/js/components/common/values-box.js +++ b/web/public/js/components/common/values-box.js @@ -2,7 +2,7 @@ Vue.component("values-box", { props: ["values", "size", "maxlength", "name"], data: function () { let values = this.values; - if (typeof (values) != "object") { + if (values == null) { values = []; } return { diff --git a/web/views/@default/clusters/cluster/@menu.html b/web/views/@default/clusters/cluster/@menu.html index a9e8ed1f..f5e7b19d 100644 --- a/web/views/@default/clusters/cluster/@menu.html +++ b/web/views/@default/clusters/cluster/@menu.html @@ -1,6 +1,5 @@ 节点列表 - 添加节点 - + 创建节点 安装节点 \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/createBatch.css b/web/views/@default/clusters/cluster/createBatch.css new file mode 100644 index 00000000..81bb03da --- /dev/null +++ b/web/views/@default/clusters/cluster/createBatch.css @@ -0,0 +1,7 @@ +.left-box { + top: 10em; +} +.right-box { + top: 10em; +} +/*# sourceMappingURL=createBatch.css.map */ \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/createBatch.css.map b/web/views/@default/clusters/cluster/createBatch.css.map new file mode 100644 index 00000000..15c605ec --- /dev/null +++ b/web/views/@default/clusters/cluster/createBatch.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["createBatch.less"],"names":[],"mappings":"AAAA;EACC,SAAA;;AAGD;EACC,SAAA","file":"createBatch.css"} \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/createBatch.html b/web/views/@default/clusters/cluster/createBatch.html new file mode 100644 index 00000000..f08684ee --- /dev/null +++ b/web/views/@default/clusters/cluster/createBatch.html @@ -0,0 +1,19 @@ +{$layout} +{$template "/clusters/cluster/menu"} +{$template "/left_menu"} + +
+
+ + + + + + +
节点IP列表 + +

每行一个节点IP。

+
+ +
+
\ No newline at end of file diff --git a/web/views/@default/clusters/cluster/createBatch.js b/web/views/@default/clusters/cluster/createBatch.js new file mode 100644 index 00000000..c87ab581 --- /dev/null +++ b/web/views/@default/clusters/cluster/createBatch.js @@ -0,0 +1,7 @@ +Tea.context(function () { + this.success = NotifySuccess("保存成功", "/clusters/cluster?clusterId=" + this.clusterId) + + this.$delay(function () { + this.$refs.ipList.focus() + }) +}) \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/createBatch.less b/web/views/@default/clusters/cluster/createBatch.less new file mode 100644 index 00000000..f54837f3 --- /dev/null +++ b/web/views/@default/clusters/cluster/createBatch.less @@ -0,0 +1,7 @@ +.left-box { + top: 10em; +} + +.right-box { + top: 10em; +} \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/createNode.css b/web/views/@default/clusters/cluster/createNode.css new file mode 100644 index 00000000..e2dadd67 --- /dev/null +++ b/web/views/@default/clusters/cluster/createNode.css @@ -0,0 +1,7 @@ +.left-box { + top: 10em; +} +.right-box { + top: 10em; +} +/*# sourceMappingURL=createNode.css.map */ \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/createNode.css.map b/web/views/@default/clusters/cluster/createNode.css.map new file mode 100644 index 00000000..fd804f17 --- /dev/null +++ b/web/views/@default/clusters/cluster/createNode.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["createNode.less"],"names":[],"mappings":"AAAA;EACC,SAAA;;AAGD;EACC,SAAA","file":"createNode.css"} \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/createNode.html b/web/views/@default/clusters/cluster/createNode.html new file mode 100644 index 00000000..821826d4 --- /dev/null +++ b/web/views/@default/clusters/cluster/createNode.html @@ -0,0 +1,49 @@ +{$layout} +{$template "/clusters/cluster/menu"} +{$template "/left_menu"} + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
节点名称 * + +
IP地址 + +
SSH主机地址 + +

比如192.168.1.100

+
SSH主机端口 + +

常见的比如22。

+
SSH登录认证 + +
+ +
+
\ No newline at end of file diff --git a/web/views/@default/clusters/cluster/node/create.js b/web/views/@default/clusters/cluster/createNode.js similarity index 100% rename from web/views/@default/clusters/cluster/node/create.js rename to web/views/@default/clusters/cluster/createNode.js diff --git a/web/views/@default/clusters/cluster/createNode.less b/web/views/@default/clusters/cluster/createNode.less new file mode 100644 index 00000000..f54837f3 --- /dev/null +++ b/web/views/@default/clusters/cluster/createNode.less @@ -0,0 +1,7 @@ +.left-box { + top: 10em; +} + +.right-box { + top: 10em; +} \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/installNodes.css b/web/views/@default/clusters/cluster/installNodes.css new file mode 100644 index 00000000..14854210 --- /dev/null +++ b/web/views/@default/clusters/cluster/installNodes.css @@ -0,0 +1,7 @@ +.left-box { + top: 10em; +} +.right-box { + top: 10em; +} +/*# sourceMappingURL=installNodes.css.map */ \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/installNodes.css.map b/web/views/@default/clusters/cluster/installNodes.css.map new file mode 100644 index 00000000..c612048b --- /dev/null +++ b/web/views/@default/clusters/cluster/installNodes.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["installNodes.less"],"names":[],"mappings":"AAAA;EACC,SAAA;;AAGD;EACC,SAAA","file":"installNodes.css"} \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/installNodes.html b/web/views/@default/clusters/cluster/installNodes.html index 858f4cbf..da1b900b 100644 --- a/web/views/@default/clusters/cluster/installNodes.html +++ b/web/views/@default/clusters/cluster/installNodes.html @@ -1,7 +1,9 @@ {$layout} +{$template "menu"} +{$template "/left_menu"} - {$template "menu"} -

可以通过节点安装包中的configs/cluster.yaml直接自动注册节点。

+
+

在官网下载节点安装包,然后通过修改节点安装包中的configs/cluster.yaml,启动后会自动注册节点。

-
cluster.yaml
@@ -9,9 +11,10 @@
rpc:
-  endpoints: [ {{cluster.endpoints}} ]
-clusterId: "{{cluster.uniqueId}}"
-secret: "{{cluster.secret}}"
+ endpoints: [ {{cluster.endpoints}} ] + clusterId: "{{cluster.uniqueId}}" + secret: "{{cluster.secret}}"
\ No newline at end of file + +
diff --git a/web/views/@default/clusters/cluster/installNodes.less b/web/views/@default/clusters/cluster/installNodes.less new file mode 100644 index 00000000..f54837f3 --- /dev/null +++ b/web/views/@default/clusters/cluster/installNodes.less @@ -0,0 +1,7 @@ +.left-box { + top: 10em; +} + +.right-box { + top: 10em; +} \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/installRemote.css b/web/views/@default/clusters/cluster/installRemote.css new file mode 100644 index 00000000..8756a5a3 --- /dev/null +++ b/web/views/@default/clusters/cluster/installRemote.css @@ -0,0 +1,7 @@ +.left-box { + top: 10em; +} +.right-box { + top: 10em; +} +/*# sourceMappingURL=installRemote.css.map */ \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/installRemote.css.map b/web/views/@default/clusters/cluster/installRemote.css.map new file mode 100644 index 00000000..8f6f01ec --- /dev/null +++ b/web/views/@default/clusters/cluster/installRemote.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["installRemote.less"],"names":[],"mappings":"AAAA;EACC,SAAA;;AAGD;EACC,SAAA","file":"installRemote.css"} \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/installRemote.html b/web/views/@default/clusters/cluster/installRemote.html new file mode 100644 index 00000000..9ef5282b --- /dev/null +++ b/web/views/@default/clusters/cluster/installRemote.html @@ -0,0 +1,48 @@ +{$layout} +{$template "menu"} +{$template "/left_menu"} + +
+

暂时没有需要远程安装的节点。

+ +
+

所有未安装节点

+ + + + + + + + + + + + + + + + + +
节点名访问IPSSH地址节点状态操作
{{node.name}} + {{addr.ip}} + + + {{node.loginParams.host}}:{{node.loginParams.port}} + + 没有设置 + +
+
安装中...
+
+ 已安装成功 + 安装过程中发生错误:{{node.installStatus.error}} +
+
+
+ 安装 + 安装中... + 安装 +
+
+
diff --git a/web/views/@default/clusters/cluster/installRemote.js b/web/views/@default/clusters/cluster/installRemote.js new file mode 100644 index 00000000..bfd129d0 --- /dev/null +++ b/web/views/@default/clusters/cluster/installRemote.js @@ -0,0 +1,73 @@ +Tea.context(function () { + this.isInstalling = false + let installingNode = null + + this.$delay(function () { + this.reload() + }) + + this.installNode = function (node) { + let that = this + teaweb.confirm("确定要开始安装此节点吗?", function () { + installingNode = node + that.isInstalling = true + node.isInstalling = true + + that.$post("$") + .params({ + nodeId: node.id + }) + }) + } + + this.reload = function () { + let that = this + if (installingNode != null) { + this.$post("/clusters/cluster/installStatus") + .params({ + nodeId: installingNode.id + }) + .success(function (resp) { + if (resp.data.status != null) { + installingNode.installStatus = resp.data.status + if (installingNode.installStatus.isFinished) { + if (installingNode.installStatus.isOk) { + installingNode = null + teaweb.success("安装成功", function () { + window.location.reload() + }) + } else { + let nodeId = installingNode.id + let errMsg = installingNode.installStatus.error + that.isInstalling = false + installingNode.isInstalling = false + installingNode = null + + switch (resp.data.status.errorCode) { + case "EMPTY_LOGIN": + case "EMPTY_SSH_HOST": + case "EMPTY_SSH_PORT": + case "EMPTY_GRANT": + teaweb.warn("需要填写SSH登录信息", function () { + teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, { + callback: function () { + teaweb.reload() + } + }) + }) + return + default: + teaweb.warn("安装失败:" + errMsg) + } + } + } + } + }) + .done(function () { + setTimeout(this.reload, 3000) + }) + } else { + setTimeout(this.reload, 3000) + } + } +}) \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/installRemote.less b/web/views/@default/clusters/cluster/installRemote.less new file mode 100644 index 00000000..f54837f3 --- /dev/null +++ b/web/views/@default/clusters/cluster/installRemote.less @@ -0,0 +1,7 @@ +.left-box { + top: 10em; +} + +.right-box { + top: 10em; +} \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/node/create.html b/web/views/@default/clusters/cluster/node/create.html deleted file mode 100644 index 08ace998..00000000 --- a/web/views/@default/clusters/cluster/node/create.html +++ /dev/null @@ -1,42 +0,0 @@ -{$layout} - - {$template "/clusters/cluster/menu"} - -
- - - - - - - - - - - - - - - - - - - - - - -
节点名称 * - -
IP地址 - -
SSH主机地址 - -

比如192.168.1.100

-
SSH主机端口 - -

常见的比如22。

-
SSH登录认证 - -
- -
\ No newline at end of file diff --git a/web/views/@default/clusters/cluster/updateNodeSSH.html b/web/views/@default/clusters/cluster/updateNodeSSH.html new file mode 100644 index 00000000..9b0c7b24 --- /dev/null +++ b/web/views/@default/clusters/cluster/updateNodeSSH.html @@ -0,0 +1,31 @@ +{$layout "layout_popup"} + +

修改节点"{{node.name}}"的SSH登录信息

+ +
+ + + + + + + + + + + + + + + +
SSH主机地址 * + +

比如192.168.1.100

+
SSH主机端口 & + +

比如22。

+
SSH登录认证 * + +
+ +
\ No newline at end of file diff --git a/web/views/@default/clusters/cluster/updateNodeSSH.js b/web/views/@default/clusters/cluster/updateNodeSSH.js new file mode 100644 index 00000000..c8fe9515 --- /dev/null +++ b/web/views/@default/clusters/cluster/updateNodeSSH.js @@ -0,0 +1,3 @@ +Tea.context(function () { + this.success = NotifyPopup +}) \ No newline at end of file