Files
waf-platform/EdgeAdmin/web/views/@default/settings/upgrade/index.js
2026-03-22 17:37:40 +08:00

459 lines
12 KiB
JavaScript
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.

Tea.context(function () {
let that = this
// 计算总待升级数
this.totalUpgradeCount = 0
this.modules.forEach(function (mod) {
mod.expanded = true
that.totalUpgradeCount += mod.count
if (mod.clusters != null) {
mod.clusters.forEach(function (cluster) {
cluster.expanded = true
if (cluster.nodes != null) {
cluster.nodes.forEach(function (node) {
node.isUpgrading = false
node.isChecked = false
})
}
})
}
})
// 正在升级的节点ID集合按模块
this.upgradingNodeIds = {
"node": [],
"dns": [],
"httpdns": []
}
// 启动状态轮询
this.$delay(function () {
this.pollStatus()
})
/**
* 获取节点详情页URL
*/
this.nodeDetailURL = function (moduleCode, clusterId, nodeId) {
switch (moduleCode) {
case "node":
return "/clusters/cluster/node?clusterId=" + clusterId + "&nodeId=" + nodeId
case "dns":
return "/ns/clusters/cluster/node?clusterId=" + clusterId + "&nodeId=" + nodeId
case "httpdns":
return "/httpdns/clusters/cluster/node?clusterId=" + clusterId + "&nodeId=" + nodeId
default:
return "#"
}
}
/**
* 判断节点升级是否已完成(成功)
*/
this.isNodeUpgradeFinished = function (node) {
return node.installStatus != null && node.installStatus.isFinished && node.installStatus.isOk
}
/**
* 全选/取消全选
*/
this.toggleCheckAll = function (cluster) {
if (cluster.nodes == null) return
let allChecked = that.isAllChecked(cluster)
cluster.nodes.forEach(function (node) {
if (!that.isNodeUpgradeFinished(node)) {
node.isChecked = !allChecked
}
})
}
/**
* 是否全部选中
*/
this.isAllChecked = function (cluster) {
if (cluster.nodes == null || cluster.nodes.length == 0) return false
let checkableNodes = cluster.nodes.filter(function (node) {
return !that.isNodeUpgradeFinished(node)
})
if (checkableNodes.length == 0) return false
return checkableNodes.every(function (node) { return node.isChecked })
}
/**
* 计算集群内选中的节点数
*/
this.countCheckedNodesInCluster = function (cluster) {
if (cluster.nodes == null) return 0
return cluster.nodes.filter(function (node) { return node.isChecked }).length
}
/**
* 全部升级
*/
this.upgradeAll = function () {
var vue = this
teaweb.confirm("确定要升级所有模块的所有待升级节点吗?", function () {
vue.$post("/settings/upgrade/upgradeNode")
.params({
module: "",
scope: "all",
clusterId: 0,
nodeId: 0
})
.success(function () {
// 标记所有节点为升级中
that.modules.forEach(function (mod) {
if (mod.clusters != null) {
mod.clusters.forEach(function (cluster) {
if (cluster.nodes != null) {
cluster.nodes.forEach(function (node) {
node.installStatus = {
isRunning: true,
isFinished: false,
isOk: false,
error: "",
errorCode: ""
}
node.isUpgrading = true
that.trackNode(mod.code, node.id)
})
}
})
}
})
})
.fail(function (resp) {
teaweb.warn("升级请求失败:" + resp.message)
})
})
}
/**
* 按模块升级
*/
this.upgradeModule = function (moduleCode) {
var vue = this
teaweb.confirm("确定要升级该模块的所有待升级节点吗?", function () {
vue.$post("/settings/upgrade/upgradeNode")
.params({
module: moduleCode,
scope: "module",
clusterId: 0,
nodeId: 0
})
.success(function () {
that.markModuleUpgrading(moduleCode)
})
.fail(function (resp) {
teaweb.warn("升级请求失败:" + resp.message)
})
})
}
/**
* 按集群升级
*/
this.upgradeCluster = function (moduleCode, clusterId) {
var vue = this
teaweb.confirm("确定要升级该集群的所有待升级节点吗?", function () {
vue.$post("/settings/upgrade/upgradeNode")
.params({
module: moduleCode,
scope: "cluster",
clusterId: clusterId,
nodeId: 0
})
.success(function () {
that.markClusterUpgrading(moduleCode, clusterId)
})
.fail(function (resp) {
teaweb.warn("升级请求失败:" + resp.message)
})
})
}
/**
* 批量升级集群内选中的节点
*/
this.upgradeBatchInCluster = function (moduleCode, cluster) {
if (cluster.nodes == null) return
var checkedNodes = cluster.nodes.filter(function (node) { return node.isChecked })
if (checkedNodes.length == 0) return
var vue = this
teaweb.confirm("确定要批量升级选中的 " + checkedNodes.length + " 个节点吗?", function () {
checkedNodes.forEach(function (node) {
node.installStatus = {
isRunning: true,
isFinished: false,
isOk: false,
error: "",
errorCode: ""
}
node.isUpgrading = true
node.isChecked = false
that.trackNode(moduleCode, node.id)
vue.$post("/settings/upgrade/upgradeNode")
.params({
module: moduleCode,
scope: "node",
clusterId: 0,
nodeId: node.id
})
})
})
}
/**
* 升级单个节点
*/
this.upgradeNode = function (moduleCode, node) {
var vue = this
teaweb.confirm("确定要升级节点 \"" + node.name + "\" 吗?", function () {
node.installStatus = {
isRunning: true,
isFinished: false,
isOk: false,
error: "",
errorCode: ""
}
node.isUpgrading = true
that.trackNode(moduleCode, node.id)
vue.$post("/settings/upgrade/upgradeNode")
.params({
module: moduleCode,
scope: "node",
clusterId: 0,
nodeId: node.id
})
.success(function () { })
.fail(function (resp) {
node.isUpgrading = false
teaweb.warn("升级请求失败:" + resp.message)
})
})
}
/**
* 标记模块下所有节点为升级中
*/
this.markModuleUpgrading = function (moduleCode) {
that.modules.forEach(function (mod) {
if (mod.code == moduleCode && mod.clusters != null) {
mod.clusters.forEach(function (cluster) {
if (cluster.nodes != null) {
cluster.nodes.forEach(function (node) {
node.installStatus = {
isRunning: true,
isFinished: false,
isOk: false,
error: "",
errorCode: ""
}
node.isUpgrading = true
that.trackNode(moduleCode, node.id)
})
}
})
}
})
}
/**
* 标记集群下所有节点为升级中
*/
this.markClusterUpgrading = function (moduleCode, clusterId) {
that.modules.forEach(function (mod) {
if (mod.code == moduleCode && mod.clusters != null) {
mod.clusters.forEach(function (cluster) {
if (cluster.id == clusterId && cluster.nodes != null) {
cluster.nodes.forEach(function (node) {
node.installStatus = {
isRunning: true,
isFinished: false,
isOk: false,
error: "",
errorCode: ""
}
node.isUpgrading = true
that.trackNode(moduleCode, node.id)
})
}
})
}
})
}
/**
* 追踪节点升级状态
*/
this.trackNode = function (moduleCode, nodeId) {
if (that.upgradingNodeIds[moduleCode] == null) {
that.upgradingNodeIds[moduleCode] = []
}
if (that.upgradingNodeIds[moduleCode].indexOf(nodeId) < 0) {
that.upgradingNodeIds[moduleCode].push(nodeId)
}
}
/**
* 状态轮询
*/
this.pollStatus = function () {
var vue = this
// 检查是否有正在升级的节点
let hasUpgrading = false
for (let key in that.upgradingNodeIds) {
if (that.upgradingNodeIds[key].length > 0) {
hasUpgrading = true
break
}
}
if (!hasUpgrading) {
setTimeout(function () { that.pollStatus() }, 5000)
return
}
vue.$post("/settings/upgrade/status")
.params({
nodeIdsJSON: JSON.stringify(that.upgradingNodeIds)
})
.success(function (resp) {
let statuses = resp.data.statuses
if (statuses == null) {
return
}
// 更新各模块节点状态
for (let moduleCode in statuses) {
let nodeStatuses = statuses[moduleCode]
if (nodeStatuses == null) {
continue
}
nodeStatuses.forEach(function (ns) {
that.updateNodeStatus(moduleCode, ns.id, ns.installStatus)
})
}
})
.done(function () {
setTimeout(function () { that.pollStatus() }, 3000)
})
}
/**
* 更新节点安装状态
*/
this.updateNodeStatus = function (moduleCode, nodeId, installStatus) {
that.modules.forEach(function (mod) {
if (mod.code == moduleCode && mod.clusters != null) {
mod.clusters.forEach(function (cluster) {
if (cluster.nodes != null) {
cluster.nodes.forEach(function (node) {
if (node.id == nodeId && installStatus != null) {
node.installStatus = installStatus
// 仅在升级完成isFinished时才移除跟踪
// 不要仅凭 !isRunning 就移除,因为批量升级时排队的节点尚未开始
if (installStatus.isFinished) {
node.isUpgrading = false
let idx = that.upgradingNodeIds[moduleCode].indexOf(nodeId)
if (idx >= 0) {
that.upgradingNodeIds[moduleCode].splice(idx, 1)
}
if (installStatus.isOk) {
// 升级成功,延迟后从列表中移除
setTimeout(function () {
let nIdx = cluster.nodes.indexOf(node)
if (nIdx >= 0) {
cluster.nodes.splice(nIdx, 1)
cluster.count--
mod.count--
that.totalUpgradeCount--
if (cluster.count <= 0) {
let cIdx = mod.clusters.indexOf(cluster)
if (cIdx >= 0) {
mod.clusters.splice(cIdx, 1)
}
}
if (mod.count <= 0) {
let mIdx = that.modules.indexOf(mod)
if (mIdx >= 0) {
that.modules.splice(mIdx, 1)
}
}
}
}, 2000)
} else {
// 升级失败,根据 errorCode 给出具体提示
that.handleUpgradeError(moduleCode, node, installStatus)
}
}
}
})
}
})
}
})
}
/**
* 处理升级错误,根据 errorCode 提供更友好的提示
*/
this.handleUpgradeError = function (moduleCode, node, installStatus) {
let errorCode = installStatus.errorCode || ""
let errMsg = installStatus.error || ""
switch (errorCode) {
case "EMPTY_LOGIN":
case "EMPTY_SSH_HOST":
case "EMPTY_SSH_PORT":
case "EMPTY_GRANT":
// SSH 信息未配置的错误,不弹窗(页面上已有"没有设置"提示)
break
case "CREATE_ROOT_DIRECTORY_FAILED":
teaweb.warn("节点 \"" + node.name + "\" 创建根目录失败:" + errMsg)
break
case "INSTALL_HELPER_FAILED":
teaweb.warn("节点 \"" + node.name + "\" 安装助手失败:" + errMsg)
break
case "TEST_FAILED":
teaweb.warn("节点 \"" + node.name + "\" 环境测试失败:" + errMsg)
break
case "RPC_TEST_FAILED":
teaweb.warn("节点 \"" + node.name + "\" RPC通讯测试失败" + errMsg)
break
}
}
/**
* 更新自动升级状态
*/
this.updateAutoUpgrade = function () {
var vue = this
// @change 已经翻转了值,先记录新值并立即恢复
let newValue = that.config.autoUpgrade
that.config.autoUpgrade = !newValue
let msg = newValue ? "确定要开启自动升级功能吗?开启后节点会自动下载安装新版本。" : "确定要关闭自动升级功能吗?关闭后只能通过这里手动执行升级。"
teaweb.confirm(msg, function () {
vue.$post("/settings/upgrade")
.params({
autoUpgrade: newValue ? 1 : 0
})
.success(function () {
that.config.autoUpgrade = newValue
teaweb.successToast("设置保存成功")
})
.fail(function (resp) {
teaweb.warn("设置保存失败:" + resp.message)
})
})
}
})