mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-07 15:20:25 +08:00
实现远程升级节点
This commit is contained in:
@@ -45,6 +45,7 @@ func (this *CreateBatchAction) RunPost(params struct {
|
|||||||
IpList string
|
IpList string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
}) {
|
}) {
|
||||||
if params.ClusterId <= 0 {
|
if params.ClusterId <= 0 {
|
||||||
this.Fail("请选择正确的集群")
|
this.Fail("请选择正确的集群")
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ func init() {
|
|||||||
GetPost("/installNodes", new(InstallNodesAction)).
|
GetPost("/installNodes", new(InstallNodesAction)).
|
||||||
GetPost("/installRemote", new(InstallRemoteAction)).
|
GetPost("/installRemote", new(InstallRemoteAction)).
|
||||||
Post("/installStatus", new(InstallStatusAction)).
|
Post("/installStatus", new(InstallStatusAction)).
|
||||||
|
GetPost("/upgradeRemote", new(UpgradeRemoteAction)).
|
||||||
|
Post("/upgradeStatus", new(UpgradeStatusAction)).
|
||||||
GetPost("/delete", new(DeleteAction)).
|
GetPost("/delete", new(DeleteAction)).
|
||||||
GetPost("/createNode", new(CreateNodeAction)).
|
GetPost("/createNode", new(CreateNodeAction)).
|
||||||
GetPost("/createBatch", new(CreateBatchAction)).
|
GetPost("/createBatch", new(CreateBatchAction)).
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package cluster
|
package cluster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
@@ -20,18 +19,7 @@ func (this *InstallNodesAction) Init() {
|
|||||||
func (this *InstallNodesAction) RunGet(params struct {
|
func (this *InstallNodesAction) RunGet(params struct {
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
}) {
|
}) {
|
||||||
this.Data["leftMenuItems"] = []maps.Map{
|
this.Data["leftMenuItems"] = LeftMenuItemsForInstall(params.ClusterId, "register")
|
||||||
{
|
|
||||||
"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})
|
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{ClusterId: params.ClusterId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package cluster
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
@@ -21,18 +20,7 @@ func (this *InstallRemoteAction) Init() {
|
|||||||
func (this *InstallRemoteAction) RunGet(params struct {
|
func (this *InstallRemoteAction) RunGet(params struct {
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
}) {
|
}) {
|
||||||
this.Data["leftMenuItems"] = []maps.Map{
|
this.Data["leftMenuItems"] = LeftMenuItemsForInstall(params.ClusterId, "install")
|
||||||
{
|
|
||||||
"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})
|
nodesResp, err := this.RPC().NodeRPC().FindAllNotInstalledNodesWithClusterId(this.AdminContext(), &pb.FindAllNotInstalledNodesWithClusterIdRequest{ClusterId: params.ClusterId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpgradeRemoteAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeRemoteAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeRemoteAction) RunGet(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
}) {
|
||||||
|
this.Data["leftMenuItems"] = LeftMenuItemsForInstall(params.ClusterId, "upgrade")
|
||||||
|
|
||||||
|
nodes := []maps.Map{}
|
||||||
|
resp, err := this.RPC().NodeRPC().FindAllUpgradeNodesWithClusterId(this.AdminContext(), &pb.FindAllUpgradeNodesWithClusterIdRequest{ClusterId: params.ClusterId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, node := range resp.Nodes {
|
||||||
|
loginParams := maps.Map{}
|
||||||
|
if node.Node.Login != nil && len(node.Node.Login.Params) > 0 {
|
||||||
|
err := json.Unmarshal(node.Node.Login.Params, &loginParams)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes = append(nodes, maps.Map{
|
||||||
|
"id": node.Node.Id,
|
||||||
|
"name": node.Node.Name,
|
||||||
|
"os": node.Os,
|
||||||
|
"arch": node.Arch,
|
||||||
|
"oldVersion": node.OldVersion,
|
||||||
|
"newVersion": node.NewVersion,
|
||||||
|
"login": node.Node.Login,
|
||||||
|
"loginParams": loginParams,
|
||||||
|
"addresses": node.Node.IpAddresses,
|
||||||
|
"installStatus": node.Node.InstallStatus,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["nodes"] = nodes
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeRemoteAction) RunPost(params struct {
|
||||||
|
NodeId int64
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
_, err := this.RPC().NodeRPC().UpgradeNode(this.AdminContext(), &pb.UpgradeNodeRequest{NodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -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 UpgradeStatusAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeStatusAction) 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()
|
||||||
|
}
|
||||||
27
internal/web/actions/default/clusters/cluster/utils.go
Normal file
27
internal/web/actions/default/clusters/cluster/utils.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package cluster
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 安装升级相关的左侧菜单
|
||||||
|
func LeftMenuItemsForInstall(clusterId int64, selectedItem string) []maps.Map {
|
||||||
|
return []maps.Map{
|
||||||
|
{
|
||||||
|
"name": "自动注册",
|
||||||
|
"url": "/clusters/cluster/installNodes?clusterId=" + numberutils.FormatInt64(clusterId),
|
||||||
|
"isActive": selectedItem == "register",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "远程安装",
|
||||||
|
"url": "/clusters/cluster/installRemote?clusterId=" + numberutils.FormatInt64(clusterId),
|
||||||
|
"isActive": selectedItem == "install",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "远程升级",
|
||||||
|
"url": "/clusters/cluster/upgradeRemote?clusterId=" + numberutils.FormatInt64(clusterId),
|
||||||
|
"isActive": selectedItem == "upgrade",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<second-menu>
|
<second-menu>
|
||||||
<menu-item :href="'/clusters/cluster?clusterId=' + clusterId" code="index">节点列表</menu-item>
|
<menu-item :href="'/clusters/cluster?clusterId=' + clusterId" code="index">节点列表</menu-item>
|
||||||
<menu-item :href="'/clusters/cluster/createNode?clusterId=' + clusterId" code="create">创建节点</menu-item>
|
<menu-item :href="'/clusters/cluster/createNode?clusterId=' + clusterId" code="create">创建节点</menu-item>
|
||||||
<menu-item :href="'/clusters/cluster/installNodes?clusterId=' + clusterId" code="install">安装节点</menu-item>
|
<menu-item :href="'/clusters/cluster/installNodes?clusterId=' + clusterId" code="install">安装升级</menu-item>
|
||||||
</second-menu>
|
</second-menu>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
<div class="right-box">
|
<div class="right-box">
|
||||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<csrf-token></csrf-token>
|
||||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||||
<table class="ui table definition selectable">
|
<table class="ui table definition selectable">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -18,7 +18,9 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr v-for="node in nodes">
|
<tr v-for="node in nodes">
|
||||||
<td>{{node.name}}</td>
|
<td>
|
||||||
|
<a :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id">{{node.name}}</a>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-for="addr in node.addresses" v-if="addr.canAccess" class="ui label tiny">{{addr.ip}}</span>
|
<span v-for="addr in node.addresses" v-if="addr.canAccess" class="ui label tiny">{{addr.ip}}</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -36,6 +38,7 @@
|
|||||||
<span v-if="!node.installStatus.isOk" class="red">安装过程中发生错误:{{node.installStatus.error}}</span>
|
<span v-if="!node.installStatus.isOk" class="red">安装过程中发生错误:{{node.installStatus.error}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span v-else class="disabled">等待安装</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="" @click.prevent="installNode(node)" v-if="!isInstalling">安装</a>
|
<a href="" @click.prevent="installNode(node)" v-if="!isInstalling">安装</a>
|
||||||
|
|||||||
7
web/views/@default/clusters/cluster/upgradeRemote.css
Normal file
7
web/views/@default/clusters/cluster/upgradeRemote.css
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.left-box {
|
||||||
|
top: 10em;
|
||||||
|
}
|
||||||
|
.right-box {
|
||||||
|
top: 10em;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=upgradeRemote.css.map */
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["upgradeRemote.less"],"names":[],"mappings":"AAAA;EACC,SAAA;;AAGD;EACC,SAAA","file":"upgradeRemote.css"}
|
||||||
53
web/views/@default/clusters/cluster/upgradeRemote.html
Normal file
53
web/views/@default/clusters/cluster/upgradeRemote.html
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "menu"}
|
||||||
|
{$template "/left_menu"}
|
||||||
|
|
||||||
|
<div class="right-box">
|
||||||
|
<p class="comment" v-if="nodes.length == 0">暂时没有需要升级的节点。</p>
|
||||||
|
|
||||||
|
<div v-if="nodes.length > 0">
|
||||||
|
<h3>所有需要升级的节点</h3>
|
||||||
|
<table class="ui table selectable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>节点名</th>
|
||||||
|
<th>访问IP</th>
|
||||||
|
<th>SSH地址</th>
|
||||||
|
<th>版本变化</th>
|
||||||
|
<th class="four wide">节点状态</th>
|
||||||
|
<th class="two op">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="node in nodes">
|
||||||
|
<td>
|
||||||
|
<a :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id">{{node.name}}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span v-for="addr in node.addresses" v-if="addr.canAccess" class="ui label tiny">{{addr.ip}}</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="node.login != null && node.login.type == 'ssh' && node.loginParams != null && node.loginParams.host != null && node.loginParams.host.length > 0">
|
||||||
|
{{node.loginParams.host}}:{{node.loginParams.port}}
|
||||||
|
</span>
|
||||||
|
<span v-else class="disabled">没有设置</span>
|
||||||
|
</td>
|
||||||
|
<td>v{{node.oldVersion}} -> v{{node.newVersion}}</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="node.installStatus != null && (node.installStatus.isRunning || node.installStatus.isFinished)">
|
||||||
|
<div v-if="node.installStatus.isRunning" class="blue">升级中...</div>
|
||||||
|
<div v-if="node.installStatus.isFinished">
|
||||||
|
<span v-if="node.installStatus.isOk" class="green">已升级成功</span>
|
||||||
|
<span v-if="!node.installStatus.isOk" class="red">升级过程中发生错误:{{node.installStatus.error}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span v-else class="disabled">等待升级</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="" @click.prevent="installNode(node)" v-if="!isInstalling">升级</a>
|
||||||
|
<span v-if="isInstalling && node.isInstalling">升级中...</span>
|
||||||
|
<span v-if="isInstalling && !node.isInstalling" class="disabled">升级</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
87
web/views/@default/clusters/cluster/upgradeRemote.js
Normal file
87
web/views/@default/clusters/cluster/upgradeRemote.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
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/upgradeStatus")
|
||||||
|
.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
|
||||||
|
case "CREATE_ROOT_DIRECTORY_FAILED":
|
||||||
|
teaweb.warn("创建根目录失败,请检查目录权限或者手工创建:" + errMsg)
|
||||||
|
return
|
||||||
|
case "INSTALL_HELPER_FAILED":
|
||||||
|
teaweb.warn("安装助手失败:" + errMsg)
|
||||||
|
return
|
||||||
|
case "TEST_FAILED":
|
||||||
|
teaweb.warn("环境测试失败:" + errMsg)
|
||||||
|
return
|
||||||
|
case "RPC_TEST_FAILED":
|
||||||
|
teaweb.confirm("html:要升级的节点到API服务之间的RPC通讯测试失败,具体错误:" + errMsg + ",<br/>现在修改API信息?", function () {
|
||||||
|
window.location = "/api"
|
||||||
|
})
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
teaweb.warn("升级失败:" + errMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.done(function () {
|
||||||
|
setTimeout(this.reload, 3000)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setTimeout(this.reload, 3000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
7
web/views/@default/clusters/cluster/upgradeRemote.less
Normal file
7
web/views/@default/clusters/cluster/upgradeRemote.less
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.left-box {
|
||||||
|
top: 10em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-box {
|
||||||
|
top: 10em;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user