mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-03 20:40:26 +08:00
实现迁移辅助功能(系统设置 -- 高级设置 -- 迁移)
This commit is contained in:
@@ -40,6 +40,7 @@ func (this *AdvancedHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNex
|
||||
if teaconst.IsPlus {
|
||||
tabbar.Add("监控节点", "", "/settings/monitorNodes", "", this.tab == "monitorNodes")
|
||||
}
|
||||
tabbar.Add("迁移", "", "/settings/transfer", "", this.tab == "transfer")
|
||||
if teaconst.BuildPlus {
|
||||
tabbar.Add("商业版认证", "", "/settings/authority", "", this.tab == "authority")
|
||||
}
|
||||
|
||||
17
internal/web/actions/default/settings/transfer/index.go
Normal file
17
internal/web/actions/default/settings/transfer/index.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package transfer
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "transfer", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
23
internal/web/actions/default/settings/transfer/init.go
Normal file
23
internal/web/actions/default/settings/transfer/init.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package transfer
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
|
||||
Helper(settingutils.NewAdvancedHelper("transfer")).
|
||||
Prefix("/settings/transfer").
|
||||
Get("", new(IndexAction)).
|
||||
Post("/validateAPI", new(ValidateAPIAction)).
|
||||
Post("/updateHosts", new(UpdateHostsAction)).
|
||||
Post("/upgradeNodes", new(UpgradeNodesAction)).
|
||||
Post("/statNodes", new(StatNodesAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
23
internal/web/actions/default/settings/transfer/statNodes.go
Normal file
23
internal/web/actions/default/settings/transfer/statNodes.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package transfer
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type StatNodesAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StatNodesAction) RunPost(params struct{}) {
|
||||
countNodesResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{ActiveState: 1})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["countNodes"] = countNodesResp.Count
|
||||
|
||||
this.Success()
|
||||
}
|
||||
158
internal/web/actions/default/settings/transfer/updateHosts.go
Normal file
158
internal/web/actions/default/settings/transfer/updateHosts.go
Normal file
@@ -0,0 +1,158 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package transfer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
)
|
||||
|
||||
type UpdateHostsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateHostsAction) RunPost(params struct {
|
||||
Protocol string
|
||||
Host string
|
||||
Port string
|
||||
|
||||
OldHosts []string
|
||||
NewHosts []string
|
||||
}) {
|
||||
if len(params.OldHosts) != len(params.NewHosts) {
|
||||
this.Fail("参数配置错误,请刷新页面后重试")
|
||||
}
|
||||
|
||||
// 检查端口
|
||||
config, err := configs.LoadAPIConfig()
|
||||
if err != nil {
|
||||
this.Fail("加载当前平台的API配置失败:" + err.Error())
|
||||
}
|
||||
var apiURL = params.Protocol + "://" + configutils.QuoteIP(params.Host) + ":" + params.Port
|
||||
config.RPC.Endpoints = []string{apiURL}
|
||||
client, err := rpc.NewRPCClient(config, false)
|
||||
if err != nil {
|
||||
this.Fail("检查API节点地址出错:" + err.Error())
|
||||
}
|
||||
defer func() {
|
||||
_ = client.Close()
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
this.FailField("host", "测试API节点时出错,请检查配置,错误信息:"+err.Error())
|
||||
}
|
||||
_, err = client.APINodeRPC().FindCurrentAPINodeVersion(client.APIContext(0), &pb.FindCurrentAPINodeVersionRequest{})
|
||||
if err != nil {
|
||||
this.FailField("host", "无法连接此API节点,错误信息:"+err.Error())
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = client.Close()
|
||||
}()
|
||||
|
||||
// API节点列表
|
||||
nodesResp, err := client.APINodeRPC().FindAllEnabledAPINodes(client.Context(0), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
this.Fail("获取API节点列表失败,错误信息:" + err.Error())
|
||||
}
|
||||
var endpoints = []string{}
|
||||
for _, node := range nodesResp.ApiNodes {
|
||||
if !node.IsOn {
|
||||
continue
|
||||
}
|
||||
|
||||
// http
|
||||
if len(node.HttpJSON) > 0 {
|
||||
for index, oldHost := range params.OldHosts {
|
||||
if len(params.NewHosts[index]) == 0 {
|
||||
continue
|
||||
}
|
||||
node.HttpJSON = bytes.ReplaceAll(node.HttpJSON, []byte("\""+oldHost+"\""), []byte("\""+params.NewHosts[index]+"\""))
|
||||
}
|
||||
}
|
||||
|
||||
// https
|
||||
if len(node.HttpsJSON) > 0 {
|
||||
for index, oldHost := range params.OldHosts {
|
||||
if len(params.NewHosts[index]) == 0 {
|
||||
continue
|
||||
}
|
||||
node.HttpsJSON = bytes.ReplaceAll(node.HttpsJSON, []byte("\""+oldHost+"\""), []byte("\""+params.NewHosts[index]+"\""))
|
||||
}
|
||||
}
|
||||
|
||||
// restHTTP
|
||||
if len(node.RestHTTPJSON) > 0 {
|
||||
for index, oldHost := range params.OldHosts {
|
||||
if len(params.NewHosts[index]) == 0 {
|
||||
continue
|
||||
}
|
||||
node.RestHTTPJSON = bytes.ReplaceAll(node.RestHTTPJSON, []byte("\""+oldHost+"\""), []byte("\""+params.NewHosts[index]+"\""))
|
||||
}
|
||||
}
|
||||
|
||||
// restHTTPS
|
||||
if len(node.RestHTTPSJSON) > 0 {
|
||||
for index, oldHost := range params.OldHosts {
|
||||
if len(params.NewHosts[index]) == 0 {
|
||||
continue
|
||||
}
|
||||
node.RestHTTPSJSON = bytes.ReplaceAll(node.RestHTTPSJSON, []byte("\""+oldHost+"\""), []byte("\""+params.NewHosts[index]+"\""))
|
||||
}
|
||||
}
|
||||
|
||||
// access addrs
|
||||
if len(node.AccessAddrsJSON) > 0 {
|
||||
for index, oldHost := range params.OldHosts {
|
||||
if len(params.NewHosts[index]) == 0 {
|
||||
continue
|
||||
}
|
||||
node.AccessAddrsJSON = bytes.ReplaceAll(node.AccessAddrsJSON, []byte("\""+oldHost+"\""), []byte("\""+params.NewHosts[index]+"\""))
|
||||
}
|
||||
|
||||
var addrs []*serverconfigs.NetworkAddressConfig
|
||||
err = json.Unmarshal(node.AccessAddrsJSON, &addrs)
|
||||
if err != nil {
|
||||
this.Fail("读取节点访问地址失败:" + err.Error())
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
err = addr.Init()
|
||||
if err != nil {
|
||||
// 暂时不提示错误
|
||||
continue
|
||||
}
|
||||
for _, a := range addr.FullAddresses() {
|
||||
if !lists.ContainsString(endpoints, a) {
|
||||
endpoints = append(endpoints, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 保存
|
||||
_, err = client.APINodeRPC().UpdateAPINode(client.Context(0), &pb.UpdateAPINodeRequest{
|
||||
ApiNodeId: node.Id,
|
||||
Name: node.Name,
|
||||
Description: node.Description,
|
||||
HttpJSON: node.HttpJSON,
|
||||
HttpsJSON: node.HttpsJSON,
|
||||
AccessAddrsJSON: node.AccessAddrsJSON,
|
||||
IsOn: node.IsOn,
|
||||
RestIsOn: node.RestIsOn,
|
||||
RestHTTPJSON: node.RestHTTPJSON,
|
||||
RestHTTPSJSON: node.RestHTTPSJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("保存API节点信息失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package transfer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type UpgradeNodesAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpgradeNodesAction) RunPost(params struct {
|
||||
ApiNodeProtocol string
|
||||
ApiNodeHost string
|
||||
ApiNodePort int
|
||||
}) {
|
||||
nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), &pb.ListEnabledNodesMatchRequest{
|
||||
ActiveState: 1,
|
||||
Size: 100,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var nodes = nodesResp.Nodes
|
||||
this.Data["hasNext"] = len(nodes) > 0
|
||||
this.Data["count"] = len(nodes)
|
||||
|
||||
if len(nodes) > 0 {
|
||||
var message = &messageconfigs.ChangeAPINodeMessage{
|
||||
Addr: params.ApiNodeProtocol + "://" + configutils.QuoteIP(params.ApiNodeHost) + ":" + types.String(params.ApiNodePort),
|
||||
}
|
||||
messageJSON, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, node := range nodesResp.Nodes {
|
||||
resp, err := this.RPC().NodeRPC().SendCommandToNode(this.AdminContext(), &pb.NodeStreamMessage{
|
||||
NodeId: node.Id,
|
||||
TimeoutSeconds: 3,
|
||||
Code: messageconfigs.MessageCodeChangeAPINode,
|
||||
DataJSON: messageJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !resp.IsOk {
|
||||
this.Fail(resp.Message)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
152
internal/web/actions/default/settings/transfer/validateAPI.go
Normal file
152
internal/web/actions/default/settings/transfer/validateAPI.go
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package transfer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type ValidateAPIAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ValidateAPIAction) RunPost(params struct {
|
||||
Host string
|
||||
Port string
|
||||
Protocol string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("newAPINodeHost", params.Host).
|
||||
Require("请输入新的API节点IP或域名").
|
||||
Field("newAPINodePort", params.Port).
|
||||
Require("请输入新的API节点端口")
|
||||
|
||||
if !regexp.MustCompile(`^\d{1,5}$`).MatchString(params.Port) {
|
||||
this.FailField("newAPINodePort", "请输入正确的端口")
|
||||
}
|
||||
|
||||
// 检查端口
|
||||
config, err := configs.LoadAPIConfig()
|
||||
if err != nil {
|
||||
this.Fail("加载当前平台的API配置失败:" + err.Error())
|
||||
}
|
||||
config.RPC.Endpoints = []string{params.Protocol + "://" + configutils.QuoteIP(params.Host) + ":" + params.Port}
|
||||
client, err := rpc.NewRPCClient(config, false)
|
||||
if err != nil {
|
||||
this.Fail("检查API节点地址出错:" + err.Error())
|
||||
}
|
||||
defer func() {
|
||||
_ = client.Close()
|
||||
}()
|
||||
|
||||
_, err = client.AdminRPC().FindAdminFullname(this.AdminContext(), &pb.FindAdminFullnameRequest{AdminId: this.AdminId()})
|
||||
if err != nil {
|
||||
statusErr, ok := status.FromError(err)
|
||||
if ok {
|
||||
if statusErr.Code() == codes.Unavailable {
|
||||
this.Fail("测试新API节点失败:无法连接新的API节点:请检查:1、API节点地址和端口是否正确;2、防火墙或安全策略是否已正确设置。详细原因:" + err.Error())
|
||||
}
|
||||
}
|
||||
this.Fail("测试新API节点失败:" + err.Error())
|
||||
}
|
||||
|
||||
// 所有API节点
|
||||
apiNodesResp, err := client.APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var apiNodes = apiNodesResp.ApiNodes
|
||||
var hosts = []string{}
|
||||
for _, node := range apiNodes {
|
||||
if !node.IsOn {
|
||||
continue
|
||||
}
|
||||
|
||||
// http
|
||||
if len(node.HttpJSON) > 0 {
|
||||
var config = &serverconfigs.HTTPProtocolConfig{}
|
||||
err = json.Unmarshal(node.HttpJSON, config)
|
||||
if err != nil {
|
||||
this.Fail("读取节点HTTP信息失败:" + err.Error())
|
||||
}
|
||||
for _, listen := range config.Listen {
|
||||
if len(listen.Host) > 0 && !lists.ContainsString(hosts, listen.Host) {
|
||||
hosts = append(hosts, listen.Host)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https
|
||||
if len(node.HttpsJSON) > 0 {
|
||||
var config = &serverconfigs.HTTPSProtocolConfig{}
|
||||
err = json.Unmarshal(node.HttpsJSON, config)
|
||||
if err != nil {
|
||||
this.Fail("读取节点HTTPS信息失败:" + err.Error())
|
||||
}
|
||||
for _, listen := range config.Listen {
|
||||
if len(listen.Host) > 0 && !lists.ContainsString(hosts, listen.Host) {
|
||||
hosts = append(hosts, listen.Host)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restHTTP
|
||||
if len(node.RestHTTPJSON) > 0 {
|
||||
var config = &serverconfigs.HTTPProtocolConfig{}
|
||||
err = json.Unmarshal(node.RestHTTPJSON, config)
|
||||
if err != nil {
|
||||
this.Fail("读取节点REST HTTP信息失败:" + err.Error())
|
||||
}
|
||||
for _, listen := range config.Listen {
|
||||
if len(listen.Host) > 0 && !lists.ContainsString(hosts, listen.Host) {
|
||||
hosts = append(hosts, listen.Host)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restHTTPS
|
||||
if len(node.RestHTTPSJSON) > 0 {
|
||||
var config = &serverconfigs.HTTPSProtocolConfig{}
|
||||
err = json.Unmarshal(node.RestHTTPSJSON, config)
|
||||
if err != nil {
|
||||
this.Fail("读取节点REST HTTPS信息失败:" + err.Error())
|
||||
}
|
||||
for _, listen := range config.Listen {
|
||||
if len(listen.Host) > 0 && !lists.ContainsString(hosts, listen.Host) {
|
||||
hosts = append(hosts, listen.Host)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// access addrs
|
||||
if len(node.AccessAddrsJSON) > 0 {
|
||||
var addrs []*serverconfigs.NetworkAddressConfig
|
||||
err = json.Unmarshal(node.AccessAddrsJSON, &addrs)
|
||||
if err != nil {
|
||||
this.Fail("读取节点访问地址失败:" + err.Error())
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if len(addr.Host) > 0 && !lists.ContainsString(hosts, addr.Host) {
|
||||
hosts = append(hosts, addr.Host)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["hosts"] = hosts
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -117,6 +117,7 @@ import (
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/profile"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/security"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/server"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/transfer"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/ui"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/upgrade"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/user-ui"
|
||||
|
||||
Reference in New Issue
Block a user