将API设置URL从/api改为/settings/api

This commit is contained in:
刘祥超
2023-06-05 09:41:52 +08:00
parent 8c064daf3f
commit aaff8f0c4a
45 changed files with 31 additions and 31 deletions

View File

@@ -0,0 +1,67 @@
package node
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
"net"
"net/url"
"regexp"
"strings"
)
// CreateAddrPopupAction 添加地址
type CreateAddrPopupAction struct {
actionutils.ParentAction
}
func (this *CreateAddrPopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreateAddrPopupAction) RunGet(params struct {
}) {
this.Show()
}
func (this *CreateAddrPopupAction) RunPost(params struct {
Protocol string
Addr string
Must *actions.Must
}) {
params.Must.
Field("addr", params.Addr).
Require("请输入访问地址")
// 兼容URL
if regexp.MustCompile(`^(?i)(http|https)://`).MatchString(params.Addr) {
u, err := url.Parse(params.Addr)
if err != nil {
this.FailField("addr", "错误的访问地址不需要添加http://或https://")
}
params.Addr = u.Host
}
// 自动添加端口
if !strings.Contains(params.Addr, ":") {
switch params.Protocol {
case "http":
params.Addr += ":80"
case "https":
params.Addr += ":443"
}
}
host, port, err := net.SplitHostPort(params.Addr)
if err != nil {
this.FailField("addr", "错误的访问地址")
}
var addrConfig = &serverconfigs.NetworkAddressConfig{
Protocol: serverconfigs.Protocol(params.Protocol),
Host: host,
PortRange: port,
}
this.Data["addr"] = addrConfig
this.Success()
}

View File

@@ -0,0 +1,217 @@
package node
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"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/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/lists"
)
type CreatePopupAction struct {
actionutils.ParentAction
}
func (this *CreatePopupAction) Init() {
this.Nav("", "node", "create")
}
func (this *CreatePopupAction) RunGet(params struct{}) {
this.Show()
}
func (this *CreatePopupAction) RunPost(params struct {
Name string
Description string
ListensJSON []byte
CertIdsJSON []byte
AccessAddrsJSON []byte
RestIsOn bool
RestListensJSON []byte
IsOn bool
Must *actions.Must
}) {
params.Must.
Field("name", params.Name).
Require("请输入API节点名称")
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
// 监听地址
var listens = []*serverconfigs.NetworkAddressConfig{}
err := json.Unmarshal(params.ListensJSON, &listens)
if err != nil {
this.ErrorPage(err)
return
}
if len(listens) == 0 {
this.Fail("请添加至少一个进程监听地址")
}
for _, addr := range listens {
if addr.Protocol.IsHTTPFamily() {
httpConfig.IsOn = true
httpConfig.Listen = append(httpConfig.Listen, addr)
} else if addr.Protocol.IsHTTPSFamily() {
httpsConfig.IsOn = true
httpsConfig.Listen = append(httpsConfig.Listen, addr)
}
}
// Rest监听地址
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
if params.RestIsOn {
var restListens = []*serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal(params.RestListensJSON, &restListens)
if err != nil {
this.ErrorPage(err)
return
}
if len(restListens) == 0 {
this.Fail("请至少添加一个HTTP API监听端口")
return
}
for _, addr := range restListens {
if addr.Protocol.IsHTTPFamily() {
restHTTPConfig.IsOn = true
restHTTPConfig.Listen = append(restHTTPConfig.Listen, addr)
} else if addr.Protocol.IsHTTPSFamily() {
restHTTPSConfig.IsOn = true
restHTTPSConfig.Listen = append(restHTTPSConfig.Listen, addr)
}
}
// 是否有端口冲突
var rpcAddresses = []string{}
for _, listen := range listens {
err := listen.Init()
if err != nil {
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
return
}
rpcAddresses = append(rpcAddresses, listen.Addresses()...)
}
for _, listen := range restListens {
err := listen.Init()
if err != nil {
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
return
}
for _, address := range listen.Addresses() {
if lists.ContainsString(rpcAddresses, address) {
this.Fail("HTTP API地址 '" + address + "' 和 GRPC地址冲突请修改后提交")
return
}
}
}
}
// 证书
var certIds = []int64{}
if len(params.CertIdsJSON) > 0 {
err = json.Unmarshal(params.CertIdsJSON, &certIds)
if err != nil {
this.ErrorPage(err)
return
}
}
if ((httpsConfig.IsOn && len(httpsConfig.Listen) > 0) || (restHTTPSConfig.IsOn && len(httpsConfig.Listen) > 0)) && len(certIds) == 0 {
this.Fail("请添加至少一个证书")
}
var certRefs = []*sslconfigs.SSLCertRef{}
for _, certId := range certIds {
certRefs = append(certRefs, &sslconfigs.SSLCertRef{
IsOn: true,
CertId: certId,
})
}
certRefsJSON, err := json.Marshal(certRefs)
if err != nil {
this.ErrorPage(err)
return
}
// 创建策略
if len(certIds) > 0 {
sslPolicyCreateResp, err := this.RPC().SSLPolicyRPC().CreateSSLPolicy(this.AdminContext(), &pb.CreateSSLPolicyRequest{
SslCertsJSON: certRefsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
sslPolicyId := sslPolicyCreateResp.SslPolicyId
httpsConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
IsOn: true,
SSLPolicyId: sslPolicyId,
}
restHTTPSConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
IsOn: true,
SSLPolicyId: sslPolicyId,
}
}
// 访问地址
var accessAddrs = []*serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
if err != nil {
this.ErrorPage(err)
return
}
if len(accessAddrs) == 0 {
this.Fail("请添加至少一个外部访问地址")
}
httpJSON, err := json.Marshal(httpConfig)
if err != nil {
this.ErrorPage(err)
return
}
httpsJSON, err := json.Marshal(httpsConfig)
if err != nil {
this.ErrorPage(err)
return
}
restHTTPJSON, err := json.Marshal(restHTTPConfig)
if err != nil {
this.ErrorPage(err)
return
}
restHTTPSJSON, err := json.Marshal(restHTTPSConfig)
if err != nil {
this.ErrorPage(err)
return
}
createResp, err := this.RPC().APINodeRPC().CreateAPINode(this.AdminContext(), &pb.CreateAPINodeRequest{
Name: params.Name,
Description: params.Description,
HttpJSON: httpJSON,
HttpsJSON: httpsJSON,
RestIsOn: params.RestIsOn,
RestHTTPJSON: restHTTPJSON,
RestHTTPSJSON: restHTTPSJSON,
AccessAddrsJSON: params.AccessAddrsJSON,
IsOn: params.IsOn,
})
if err != nil {
this.ErrorPage(err)
return
}
// 创建日志
defer this.CreateLog(oplogs.LevelInfo, "创建API节点 %d", createResp.ApiNodeId)
this.Success()
}

View File

@@ -0,0 +1,21 @@
package node
import (
"github.com/iwind/TeaGo/actions"
"net/http"
)
type Helper struct {
}
func NewHelper() *Helper {
return &Helper{}
}
func (this *Helper) BeforeAction(action *actions.ActionObject) (goNext bool) {
if action.Request.Method != http.MethodGet {
return true
}
return true
}

View File

@@ -0,0 +1,186 @@
package node
import (
"encoding/json"
"fmt"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
"github.com/iwind/TeaGo/maps"
stringutil "github.com/iwind/TeaGo/utils/string"
"time"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "index")
}
func (this *IndexAction) RunGet(params struct {
NodeId int64
}) {
nodeResp, err := this.RPC().APINodeRPC().FindEnabledAPINode(this.AdminContext(), &pb.FindEnabledAPINodeRequest{ApiNodeId: params.NodeId})
if err != nil {
this.ErrorPage(err)
return
}
var node = nodeResp.ApiNode
if node == nil {
this.NotFound("apiNode", params.NodeId)
return
}
// 监听地址
var hasHTTPS = false
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
if len(node.HttpJSON) > 0 {
err = json.Unmarshal(node.HttpJSON, httpConfig)
if err != nil {
this.ErrorPage(err)
return
}
}
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
if len(node.HttpsJSON) > 0 {
err = json.Unmarshal(node.HttpsJSON, httpsConfig)
if err != nil {
this.ErrorPage(err)
return
}
hasHTTPS = len(httpsConfig.Listen) > 0
}
// 监听地址
var listens = []*serverconfigs.NetworkAddressConfig{}
listens = append(listens, httpConfig.Listen...)
listens = append(listens, httpsConfig.Listen...)
// 证书信息
var certs = []*sslconfigs.SSLCertConfig{}
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 {
sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{
SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId,
IgnoreData: true,
})
if err != nil {
this.ErrorPage(err)
return
}
var sslPolicyConfigJSON = sslPolicyConfigResp.SslPolicyJSON
if len(sslPolicyConfigJSON) > 0 {
var sslPolicy = &sslconfigs.SSLPolicy{}
err = json.Unmarshal(sslPolicyConfigJSON, sslPolicy)
if err != nil {
this.ErrorPage(err)
return
}
certs = sslPolicy.Certs
}
}
// 访问地址
var accessAddrs = []*serverconfigs.NetworkAddressConfig{}
if len(node.AccessAddrsJSON) > 0 {
err = json.Unmarshal(node.AccessAddrsJSON, &accessAddrs)
if err != nil {
this.ErrorPage(err)
return
}
}
// Rest地址
var restAccessAddrs = []*serverconfigs.NetworkAddressConfig{}
if node.RestIsOn {
if len(node.RestHTTPJSON) > 0 {
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
err = json.Unmarshal(node.RestHTTPJSON, httpConfig)
if err != nil {
this.ErrorPage(err)
return
}
if httpConfig.IsOn && len(httpConfig.Listen) > 0 {
restAccessAddrs = append(restAccessAddrs, httpConfig.Listen...)
}
}
if len(node.RestHTTPSJSON) > 0 {
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
err = json.Unmarshal(node.RestHTTPSJSON, httpsConfig)
if err != nil {
this.ErrorPage(err)
return
}
if httpsConfig.IsOn && len(httpsConfig.Listen) > 0 {
restAccessAddrs = append(restAccessAddrs, httpsConfig.Listen...)
}
if !hasHTTPS {
hasHTTPS = len(httpsConfig.Listen) > 0
}
}
}
// 状态
var status = &nodeconfigs.NodeStatus{}
var statusIsValid = false
this.Data["newVersion"] = ""
if len(node.StatusJSON) > 0 {
err = json.Unmarshal(node.StatusJSON, &status)
if err != nil {
this.ErrorPage(err)
return
}
if status.UpdatedAt >= time.Now().Unix()-300 {
statusIsValid = true
// 是否为新版本
if stringutil.VersionCompare(status.BuildVersion, teaconst.APINodeVersion) < 0 {
this.Data["newVersion"] = teaconst.APINodeVersion
}
}
}
this.Data["node"] = maps.Map{
"id": node.Id,
"name": node.Name,
"description": node.Description,
"isOn": node.IsOn,
"listens": listens,
"accessAddrs": accessAddrs,
"restIsOn": node.RestIsOn,
"restAccessAddrs": restAccessAddrs,
"hasHTTPS": hasHTTPS,
"certs": certs,
"isPrimary": node.IsPrimary,
"statusIsValid": statusIsValid,
"status": maps.Map{
"isActive": status.IsActive,
"updatedAt": status.UpdatedAt,
"hostname": status.Hostname,
"cpuUsage": status.CPUUsage,
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
"memUsage": status.MemoryUsage,
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
"connectionCount": status.ConnectionCount,
"buildVersion": status.BuildVersion,
"cpuPhysicalCount": status.CPUPhysicalCount,
"cpuLogicalCount": status.CPULogicalCount,
"load1m": numberutils.FormatFloat2(status.Load1m),
"load5m": numberutils.FormatFloat2(status.Load5m),
"load15m": numberutils.FormatFloat2(status.Load15m),
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
"exePath": status.ExePath,
},
}
this.Show()
}

View File

@@ -0,0 +1,33 @@
package node
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("apiNodes")).
Prefix("/settings/api/node").
// 这里不受Helper的约束
GetPost("/createAddrPopup", new(CreateAddrPopupAction)).
GetPost("/updateAddrPopup", new(UpdateAddrPopupAction)).
// 节点相关
Helper(NewHelper()).
Get("", new(IndexAction)).
GetPost("/update", new(UpdateAction)).
Get("/install", new(InstallAction)).
Get("/logs", new(LogsAction)).
GetPost("/upgradePopup", new(UpgradePopupAction)).
Post("/upgradeCheck", new(UpgradeCheckAction)).
//
EndAll()
})
}

View File

@@ -0,0 +1,57 @@
package node
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/maps"
"os"
)
type InstallAction struct {
actionutils.ParentAction
}
func (this *InstallAction) Init() {
this.Nav("", "", "install")
}
func (this *InstallAction) RunGet(params struct {
NodeId int64
}) {
// API节点信息
nodeResp, err := this.RPC().APINodeRPC().FindEnabledAPINode(this.AdminContext(), &pb.FindEnabledAPINodeRequest{ApiNodeId: params.NodeId})
if err != nil {
this.ErrorPage(err)
return
}
node := nodeResp.ApiNode
if node == nil {
this.NotFound("apiNode", params.NodeId)
return
}
this.Data["node"] = maps.Map{
"id": node.Id,
"name": node.Name,
"uniqueId": node.UniqueId,
"secret": node.Secret,
}
// 数据库配置
dbConfigMap := maps.Map{
"config": "",
"error": "",
"isNotFound": false,
}
dbConfigFile := Tea.ConfigFile("api_db.yaml")
data, err := os.ReadFile(dbConfigFile)
dbConfigMap["config"] = string(data)
if err != nil {
dbConfigMap["error"] = err.Error()
dbConfigMap["isNotFound"] = os.IsNotExist(err)
}
this.Data["dbConfig"] = dbConfigMap
this.Show()
}

View File

@@ -0,0 +1,92 @@
package node
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
)
type LogsAction struct {
actionutils.ParentAction
}
func (this *LogsAction) Init() {
this.Nav("", "node", "log")
this.SecondMenu("nodes")
}
func (this *LogsAction) RunGet(params struct {
NodeId int64
DayFrom string
DayTo string
Keyword string
Level string
}) {
this.Data["nodeId"] = params.NodeId
this.Data["dayFrom"] = params.DayFrom
this.Data["dayTo"] = params.DayTo
this.Data["keyword"] = params.Keyword
this.Data["level"] = params.Level
apiNodeResp, err := this.RPC().APINodeRPC().FindEnabledAPINode(this.AdminContext(), &pb.FindEnabledAPINodeRequest{ApiNodeId: params.NodeId})
if err != nil {
this.ErrorPage(err)
return
}
apiNode := apiNodeResp.ApiNode
if apiNode == nil {
this.NotFound("apiNode", params.NodeId)
return
}
this.Data["node"] = maps.Map{
"id": apiNode.Id,
"name": apiNode.Name,
}
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
Role: nodeconfigs.NodeRoleAPI,
NodeId: params.NodeId,
DayFrom: params.DayFrom,
DayTo: params.DayTo,
Keyword: params.Keyword,
Level: params.Level,
})
if err != nil {
this.ErrorPage(err)
return
}
count := countResp.Count
page := this.NewPage(count, 20)
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
NodeId: params.NodeId,
Role: nodeconfigs.NodeRoleAPI,
DayFrom: params.DayFrom,
DayTo: params.DayTo,
Keyword: params.Keyword,
Level: params.Level,
Offset: page.Offset,
Size: page.Size,
})
logs := []maps.Map{}
for _, log := range logsResp.NodeLogs {
logs = append(logs, maps.Map{
"tag": log.Tag,
"description": log.Description,
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
"level": log.Level,
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
})
}
this.Data["logs"] = logs
this.Data["page"] = page.AsHTML()
this.Show()
}

View File

@@ -0,0 +1,341 @@
package node
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"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/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
)
type UpdateAction struct {
actionutils.ParentAction
}
func (this *UpdateAction) Init() {
this.Nav("", "", "update")
}
func (this *UpdateAction) RunGet(params struct {
NodeId int64
}) {
nodeResp, err := this.RPC().APINodeRPC().FindEnabledAPINode(this.AdminContext(), &pb.FindEnabledAPINodeRequest{
ApiNodeId: params.NodeId,
})
if err != nil {
this.ErrorPage(err)
return
}
var node = nodeResp.ApiNode
if node == nil {
this.WriteString("要操作的节点不存在")
return
}
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
if len(node.HttpJSON) > 0 {
err = json.Unmarshal(node.HttpJSON, httpConfig)
if err != nil {
this.ErrorPage(err)
return
}
}
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
if len(node.HttpsJSON) > 0 {
err = json.Unmarshal(node.HttpsJSON, httpsConfig)
if err != nil {
this.ErrorPage(err)
return
}
}
// 监听地址
var listens = []*serverconfigs.NetworkAddressConfig{}
listens = append(listens, httpConfig.Listen...)
listens = append(listens, httpsConfig.Listen...)
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
if len(node.RestHTTPJSON) > 0 {
err = json.Unmarshal(node.RestHTTPJSON, restHTTPConfig)
if err != nil {
this.ErrorPage(err)
return
}
}
var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
if len(node.RestHTTPSJSON) > 0 {
err = json.Unmarshal(node.RestHTTPSJSON, restHTTPSConfig)
if err != nil {
this.ErrorPage(err)
return
}
}
// 监听地址
var restListens = []*serverconfigs.NetworkAddressConfig{}
restListens = append(restListens, restHTTPConfig.Listen...)
restListens = append(restListens, restHTTPSConfig.Listen...)
// 证书信息
var certs = []*sslconfigs.SSLCertConfig{}
var sslPolicyId = int64(0)
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 {
sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{
SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId,
IgnoreData: true,
})
if err != nil {
this.ErrorPage(err)
return
}
var sslPolicyConfigJSON = sslPolicyConfigResp.SslPolicyJSON
if len(sslPolicyConfigJSON) > 0 {
sslPolicyId = httpsConfig.SSLPolicyRef.SSLPolicyId
sslPolicy := &sslconfigs.SSLPolicy{}
err = json.Unmarshal(sslPolicyConfigJSON, sslPolicy)
if err != nil {
this.ErrorPage(err)
return
}
certs = sslPolicy.Certs
}
}
var accessAddrs = []*serverconfigs.NetworkAddressConfig{}
if len(node.AccessAddrsJSON) > 0 {
err = json.Unmarshal(node.AccessAddrsJSON, &accessAddrs)
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["node"] = maps.Map{
"id": node.Id,
"name": node.Name,
"description": node.Description,
"isOn": node.IsOn,
"listens": listens,
"restIsOn": node.RestIsOn,
"restListens": restListens,
"certs": certs,
"sslPolicyId": sslPolicyId,
"accessAddrs": accessAddrs,
"isPrimary": node.IsPrimary,
}
this.Show()
}
// RunPost 保存基础设置
func (this *UpdateAction) RunPost(params struct {
NodeId int64
Name string
SslPolicyId int64
ListensJSON []byte
RestIsOn bool
RestListensJSON []byte
CertIdsJSON []byte
AccessAddrsJSON []byte
Description string
IsOn bool
IsPrimary bool
Must *actions.Must
}) {
params.Must.
Field("name", params.Name).
Require("请输入API节点名称")
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
// 监听地址
var listens = []*serverconfigs.NetworkAddressConfig{}
err := json.Unmarshal(params.ListensJSON, &listens)
if err != nil {
this.ErrorPage(err)
return
}
if len(listens) == 0 {
this.Fail("请添加至少一个进程监听地址")
}
for _, addr := range listens {
if addr.Protocol.IsHTTPFamily() {
httpConfig.IsOn = true
httpConfig.Listen = append(httpConfig.Listen, addr)
} else if addr.Protocol.IsHTTPSFamily() {
httpsConfig.IsOn = true
httpsConfig.Listen = append(httpsConfig.Listen, addr)
}
}
// Rest监听地址
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
if params.RestIsOn {
var restListens = []*serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal(params.RestListensJSON, &restListens)
if err != nil {
this.ErrorPage(err)
return
}
if len(restListens) == 0 {
this.Fail("请至少添加一个HTTP API监听端口")
return
}
for _, addr := range restListens {
if addr.Protocol.IsHTTPFamily() {
restHTTPConfig.IsOn = true
restHTTPConfig.Listen = append(restHTTPConfig.Listen, addr)
} else if addr.Protocol.IsHTTPSFamily() {
restHTTPSConfig.IsOn = true
restHTTPSConfig.Listen = append(restHTTPSConfig.Listen, addr)
}
}
// 是否有端口冲突
var rpcAddresses = []string{}
for _, listen := range listens {
err := listen.Init()
if err != nil {
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
return
}
rpcAddresses = append(rpcAddresses, listen.Addresses()...)
}
for _, listen := range restListens {
err := listen.Init()
if err != nil {
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
return
}
for _, address := range listen.Addresses() {
if lists.ContainsString(rpcAddresses, address) {
this.Fail("HTTP API地址 '" + address + "' 和 GRPC地址冲突请修改后提交")
return
}
}
}
}
// 证书
var certIds = []int64{}
if len(params.CertIdsJSON) > 0 {
err = json.Unmarshal(params.CertIdsJSON, &certIds)
if err != nil {
this.ErrorPage(err)
return
}
}
if ((httpsConfig.IsOn && len(httpsConfig.Listen) > 0) || (restHTTPSConfig.IsOn && len(httpsConfig.Listen) > 0)) && len(certIds) == 0 {
this.Fail("请添加至少一个证书")
}
var certRefs = []*sslconfigs.SSLCertRef{}
for _, certId := range certIds {
certRefs = append(certRefs, &sslconfigs.SSLCertRef{
IsOn: true,
CertId: certId,
})
}
certRefsJSON, err := json.Marshal(certRefs)
if err != nil {
this.ErrorPage(err)
return
}
// 创建策略
var sslPolicyId = params.SslPolicyId
if sslPolicyId == 0 {
if len(certIds) > 0 {
sslPolicyCreateResp, err := this.RPC().SSLPolicyRPC().CreateSSLPolicy(this.AdminContext(), &pb.CreateSSLPolicyRequest{
SslCertsJSON: certRefsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
sslPolicyId = sslPolicyCreateResp.SslPolicyId
}
} else {
_, err = this.RPC().SSLPolicyRPC().UpdateSSLPolicy(this.AdminContext(), &pb.UpdateSSLPolicyRequest{
SslPolicyId: sslPolicyId,
SslCertsJSON: certRefsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
}
httpsConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
IsOn: true,
SSLPolicyId: sslPolicyId,
}
restHTTPSConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
IsOn: true,
SSLPolicyId: sslPolicyId,
}
// 访问地址
var accessAddrs = []*serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
if err != nil {
this.ErrorPage(err)
return
}
if len(accessAddrs) == 0 {
this.Fail("请添加至少一个外部访问地址")
}
httpJSON, err := json.Marshal(httpConfig)
if err != nil {
this.ErrorPage(err)
return
}
httpsJSON, err := json.Marshal(httpsConfig)
if err != nil {
this.ErrorPage(err)
return
}
restHTTPJSON, err := json.Marshal(restHTTPConfig)
if err != nil {
this.ErrorPage(err)
return
}
restHTTPSJSON, err := json.Marshal(restHTTPSConfig)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().APINodeRPC().UpdateAPINode(this.AdminContext(), &pb.UpdateAPINodeRequest{
ApiNodeId: params.NodeId,
Name: params.Name,
Description: params.Description,
HttpJSON: httpJSON,
HttpsJSON: httpsJSON,
RestIsOn: params.RestIsOn,
RestHTTPJSON: restHTTPJSON,
RestHTTPSJSON: restHTTPSJSON,
AccessAddrsJSON: params.AccessAddrsJSON,
IsOn: params.IsOn,
IsPrimary: params.IsPrimary,
})
if err != nil {
this.ErrorPage(err)
return
}
// 创建日志
defer this.CreateLog(oplogs.LevelInfo, "修改API节点 %d", params.NodeId)
this.Success()
}

View File

@@ -0,0 +1,65 @@
package node
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
"net"
"net/url"
"regexp"
"strings"
)
type UpdateAddrPopupAction struct {
actionutils.ParentAction
}
func (this *UpdateAddrPopupAction) Init() {
this.Nav("", "", "")
}
func (this *UpdateAddrPopupAction) RunGet(params struct{}) {
this.Show()
}
func (this *UpdateAddrPopupAction) RunPost(params struct {
Protocol string
Addr string
Must *actions.Must
}) {
params.Must.
Field("addr", params.Addr).
Require("请输入访问地址")
// 兼容URL
if regexp.MustCompile(`^(?i)(http|https)://`).MatchString(params.Addr) {
u, err := url.Parse(params.Addr)
if err != nil {
this.FailField("addr", "错误的访问地址不需要添加http://或https://")
}
params.Addr = u.Host
}
// 自动添加端口
if !strings.Contains(params.Addr, ":") {
switch params.Protocol {
case "http":
params.Addr += ":80"
case "https":
params.Addr += ":443"
}
}
host, port, err := net.SplitHostPort(params.Addr)
if err != nil {
this.FailField("addr", "错误的访问地址")
}
addrConfig := &serverconfigs.NetworkAddressConfig{
Protocol: serverconfigs.Protocol(params.Protocol),
Host: host,
PortRange: port,
}
this.Data["addr"] = addrConfig
this.Success()
}

View File

@@ -0,0 +1,67 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package node
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// UpgradeCheckAction 检查升级结果
type UpgradeCheckAction struct {
actionutils.ParentAction
}
func (this *UpgradeCheckAction) Init() {
this.Nav("", "", "")
}
func (this *UpgradeCheckAction) RunPost(params struct {
NodeId int64
}) {
this.Data["isOk"] = false
nodeResp, err := this.RPC().APINodeRPC().FindEnabledAPINode(this.AdminContext(), &pb.FindEnabledAPINodeRequest{ApiNodeId: params.NodeId})
if err != nil {
this.Success()
return
}
var node = nodeResp.ApiNode
if node == nil || len(node.AccessAddrs) == 0 {
this.Success()
return
}
apiConfig, err := configs.LoadAPIConfig()
if err != nil {
this.Success()
return
}
var newAPIConfig = apiConfig.Clone()
newAPIConfig.RPC.Endpoints = node.AccessAddrs
rpcClient, err := rpc.NewRPCClient(newAPIConfig, false)
if err != nil {
this.Success()
return
}
versionResp, err := rpcClient.APINodeRPC().FindCurrentAPINodeVersion(rpcClient.Context(0), &pb.FindCurrentAPINodeVersionRequest{})
if err != nil {
this.Success()
return
}
if versionResp.Version != teaconst.Version {
this.Success()
return
}
this.Data["isOk"] = true
this.Success()
}

View File

@@ -0,0 +1,124 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package node
import (
"encoding/json"
"errors"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/utils/apinodeutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"strings"
)
type UpgradePopupAction struct {
actionutils.ParentAction
}
func (this *UpgradePopupAction) Init() {
this.Nav("", "", "")
}
func (this *UpgradePopupAction) RunGet(params struct {
NodeId int64
}) {
this.Data["nodeId"] = params.NodeId
this.Data["nodeName"] = ""
this.Data["currentVersion"] = ""
this.Data["latestVersion"] = ""
this.Data["result"] = ""
this.Data["resultIsOk"] = true
this.Data["canUpgrade"] = false
this.Data["isUpgrading"] = false
nodeResp, err := this.RPC().APINodeRPC().FindEnabledAPINode(this.AdminContext(), &pb.FindEnabledAPINodeRequest{ApiNodeId: params.NodeId})
if err != nil {
this.ErrorPage(err)
return
}
var node = nodeResp.ApiNode
if node == nil {
this.Data["result"] = "要升级的节点不存在"
this.Data["resultIsOk"] = false
this.Show()
return
}
this.Data["nodeName"] = node.Name + " / [" + strings.Join(node.AccessAddrs, ", ") + "]"
// 节点状态
var status = &nodeconfigs.NodeStatus{}
if len(node.StatusJSON) > 0 {
err = json.Unmarshal(node.StatusJSON, &status)
if err != nil {
this.ErrorPage(errors.New("decode status failed: " + err.Error()))
return
}
this.Data["currentVersion"] = status.BuildVersion
} else {
this.Data["result"] = "无法检测到节点当前版本"
this.Data["resultIsOk"] = false
this.Show()
return
}
this.Data["latestVersion"] = teaconst.APINodeVersion
if status.IsActive && len(status.BuildVersion) > 0 {
canUpgrade, reason := apinodeutils.CanUpgrade(status.BuildVersion, status.OS, status.Arch)
if !canUpgrade {
this.Data["result"] = reason
this.Data["resultIsOk"] = false
this.Show()
return
}
this.Data["canUpgrade"] = true
this.Data["result"] = "等待升级"
this.Data["resultIsOk"] = true
} else {
this.Data["result"] = "当前节点非连接状态无法远程升级"
this.Data["resultIsOk"] = false
this.Show()
return
}
// 是否正在升级
var oldUpgrader = apinodeutils.SharedManager.FindUpgrader(params.NodeId)
if oldUpgrader != nil {
this.Data["result"] = "正在升级中..."
this.Data["resultIsOk"] = false
this.Data["isUpgrading"] = true
}
this.Show()
}
func (this *UpgradePopupAction) RunPost(params struct {
NodeId int64
Must *actions.Must
CSRF *actionutils.CSRF
}) {
var manager = apinodeutils.SharedManager
var oldUpgrader = manager.FindUpgrader(params.NodeId)
if oldUpgrader != nil {
this.Fail("正在升级中,无需重复提交 ...")
return
}
var upgrader = apinodeutils.NewUpgrader(params.NodeId)
manager.AddUpgrader(upgrader)
defer func() {
manager.RemoveUpgrader(upgrader)
}()
err := upgrader.Upgrade()
if err != nil {
this.Fail("升级失败:" + err.Error())
return
}
this.Success()
}