管理端全部功能跑通
This commit is contained in:
@@ -2,8 +2,6 @@ package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/policies"
|
||||
)
|
||||
|
||||
type CertsAction struct {
|
||||
@@ -15,7 +13,5 @@ func (this *CertsAction) Init() {
|
||||
}
|
||||
|
||||
func (this *CertsAction) RunGet(params struct{}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
this.Data["certs"] = policies.LoadPublicSNICertificates()
|
||||
this.Show()
|
||||
this.RedirectURL("/httpdns/clusters")
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type ClusterAction struct {
|
||||
@@ -20,19 +23,75 @@ func (this *ClusterAction) RunGet(params struct {
|
||||
Keyword string
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
cluster := pickCluster(params.ClusterId)
|
||||
|
||||
// 构建顶部 tabbar
|
||||
cluster, err := findClusterMap(this.Parent(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
httpdnsutils.AddClusterTabbar(this.Parent(), cluster.GetString("name"), params.ClusterId, "node")
|
||||
|
||||
nodes, err := listNodeMaps(this.Parent(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
nodes = filterClusterNodes(nodes, params.InstalledState, params.ActiveState, params.Keyword)
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["cluster"] = cluster
|
||||
this.Data["installState"] = params.InstalledState
|
||||
this.Data["activeState"] = params.ActiveState
|
||||
this.Data["keyword"] = params.Keyword
|
||||
nodes := mockNodes(params.ClusterId, params.InstalledState, params.ActiveState, params.Keyword)
|
||||
this.Data["nodes"] = nodes
|
||||
this.Data["hasNodes"] = len(nodes) > 0
|
||||
this.Data["page"] = ""
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func filterClusterNodes(nodes []maps.Map, installedState int, activeState int, keyword string) []maps.Map {
|
||||
keyword = strings.ToLower(strings.TrimSpace(keyword))
|
||||
|
||||
result := make([]maps.Map, 0, len(nodes))
|
||||
for _, node := range nodes {
|
||||
isInstalled := node.GetBool("isInstalled")
|
||||
if installedState == 1 && !isInstalled {
|
||||
continue
|
||||
}
|
||||
if installedState == 2 && isInstalled {
|
||||
continue
|
||||
}
|
||||
|
||||
status := node.GetMap("status")
|
||||
isOnline := node.GetBool("isOn") && node.GetBool("isUp") && status.GetBool("isActive")
|
||||
if activeState == 1 && !isOnline {
|
||||
continue
|
||||
}
|
||||
if activeState == 2 && isOnline {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(keyword) > 0 {
|
||||
hit := strings.Contains(strings.ToLower(node.GetString("name")), keyword)
|
||||
if !hit {
|
||||
ipAddresses, ok := node["ipAddresses"].([]maps.Map)
|
||||
if ok {
|
||||
for _, ipAddr := range ipAddresses {
|
||||
if strings.Contains(strings.ToLower(ipAddr.GetString("ip")), keyword) {
|
||||
hit = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hit {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, node)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -18,51 +20,37 @@ func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["currentCluster"] = maps.Map{"id": params.ClusterId, "name": "Mock Cluster"}
|
||||
|
||||
this.Data["nodeDatetime"] = "2026-02-22 12:00:00"
|
||||
this.Data["nodeTimeDiff"] = 0
|
||||
this.Data["shouldUpgrade"] = false
|
||||
this.Data["newVersion"] = ""
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": params.NodeId,
|
||||
"name": "Mock HTTPDNS Node",
|
||||
"ipAddresses": []maps.Map{{"ip": "100.200.100.200", "name": "Public IP", "canAccess": true, "isOn": true, "isUp": true}},
|
||||
"cluster": maps.Map{"id": params.ClusterId, "name": "Mock Cluster", "installDir": "/opt/edge-httpdns"},
|
||||
"installDir": "/opt/edge-httpdns",
|
||||
"isInstalled": true,
|
||||
"uniqueId": "m-1234567890",
|
||||
"secret": "mock-secret-key",
|
||||
"isOn": true,
|
||||
"isUp": true,
|
||||
"apiNodeAddrs": []string{"192.168.1.100:8001"},
|
||||
"login": nil,
|
||||
|
||||
"status": maps.Map{
|
||||
"isActive": true,
|
||||
"updatedAt": 1670000000,
|
||||
"hostname": "node-01.local",
|
||||
"cpuUsage": 0.15,
|
||||
"cpuUsageText": "15.00%",
|
||||
"memUsage": 0.45,
|
||||
"memUsageText": "45.00%",
|
||||
"connectionCount": 100,
|
||||
"buildVersion": "1.0.0",
|
||||
"cpuPhysicalCount": 4,
|
||||
"cpuLogicalCount": 8,
|
||||
"load1m": "0.50",
|
||||
"load5m": "0.60",
|
||||
"load15m": "0.70",
|
||||
"cacheTotalDiskSize": "10G",
|
||||
"cacheTotalMemorySize": "2G",
|
||||
"exePath": "/opt/edge-httpdns/bin/edge-httpdns",
|
||||
"apiSuccessPercent": 100.0,
|
||||
"apiAvgCostSeconds": 0.05,
|
||||
},
|
||||
node, err := findHTTPDNSNodeMap(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cluster, err := findHTTPDNSClusterMap(this.Parent(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["node"] = node
|
||||
this.Data["currentCluster"] = cluster
|
||||
|
||||
status := node.GetMap("status")
|
||||
updatedAt := status.GetInt64("updatedAt")
|
||||
nodeDatetime := ""
|
||||
nodeTimeDiff := int64(0)
|
||||
if updatedAt > 0 {
|
||||
nodeDatetime = timeutil.FormatTime("Y-m-d H:i:s", updatedAt)
|
||||
nodeTimeDiff = time.Now().Unix() - updatedAt
|
||||
if nodeTimeDiff < 0 {
|
||||
nodeTimeDiff = -nodeTimeDiff
|
||||
}
|
||||
}
|
||||
this.Data["nodeDatetime"] = nodeDatetime
|
||||
this.Data["nodeTimeDiff"] = nodeTimeDiff
|
||||
|
||||
this.Data["shouldUpgrade"] = false
|
||||
this.Data["newVersion"] = ""
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package node
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type InstallAction struct {
|
||||
@@ -14,28 +18,87 @@ func (this *InstallAction) Init() {
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *InstallAction) RunGet(params struct{ ClusterId int64; NodeId int64 }) {
|
||||
func (this *InstallAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
node, err := findHTTPDNSNodeMap(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cluster, err := findHTTPDNSClusterMap(this.Parent(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["currentCluster"] = maps.Map{"id": params.ClusterId, "name": "Mock Cluster"}
|
||||
this.Data["currentCluster"] = cluster
|
||||
this.Data["node"] = node
|
||||
this.Data["installStatus"] = node.GetMap("installStatus")
|
||||
|
||||
this.Data["apiEndpoints"] = "\"http://127.0.0.1:7788\""
|
||||
this.Data["sshAddr"] = "192.168.1.100:22"
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": params.NodeId,
|
||||
"name": "Mock Node",
|
||||
"isInstalled": false,
|
||||
"uniqueId": "m-1234567890",
|
||||
"secret": "mock-secret-key",
|
||||
"installDir": "/opt/edge-httpdns",
|
||||
"cluster": maps.Map{"installDir": "/opt/edge-httpdns"},
|
||||
apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["installStatus"] = nil
|
||||
|
||||
apiEndpoints := make([]string, 0, 8)
|
||||
for _, apiNode := range apiNodesResp.GetApiNodes() {
|
||||
if !apiNode.GetIsOn() {
|
||||
continue
|
||||
}
|
||||
apiEndpoints = append(apiEndpoints, apiNode.GetAccessAddrs()...)
|
||||
}
|
||||
if len(apiEndpoints) == 0 {
|
||||
apiEndpoints = []string{"http://127.0.0.1:7788"}
|
||||
}
|
||||
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
||||
this.Data["sshAddr"] = ""
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *InstallAction) RunPost(params struct{ NodeId int64 }) {
|
||||
func (this *InstallAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
nodeResp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.GetNode()
|
||||
if node == nil {
|
||||
this.Fail("节点不存在")
|
||||
return
|
||||
}
|
||||
|
||||
existingStatus := map[string]interface{}{}
|
||||
if len(node.GetInstallStatusJSON()) > 0 {
|
||||
_ = json.Unmarshal(node.GetInstallStatusJSON(), &existingStatus)
|
||||
}
|
||||
|
||||
existingStatus["isRunning"] = true
|
||||
existingStatus["isFinished"] = false
|
||||
existingStatus["isOk"] = false
|
||||
existingStatus["error"] = ""
|
||||
existingStatus["errorCode"] = ""
|
||||
existingStatus["updatedAt"] = time.Now().Unix()
|
||||
|
||||
installStatusJSON, _ := json.Marshal(existingStatus)
|
||||
_, err = this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNodeStatus(this.AdminContext(), &pb.UpdateHTTPDNSNodeStatusRequest{
|
||||
NodeId: params.NodeId,
|
||||
IsUp: node.GetIsUp(),
|
||||
IsInstalled: false,
|
||||
IsActive: node.GetIsActive(),
|
||||
StatusJSON: node.GetStatusJSON(),
|
||||
InstallStatusJSON: installStatusJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package node
|
||||
package node
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
@@ -14,18 +18,65 @@ func (this *LogsAction) Init() {
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *LogsAction) RunGet(params struct{ ClusterId int64; NodeId int64 }) {
|
||||
func (this *LogsAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
DayFrom string
|
||||
DayTo string
|
||||
Level string
|
||||
Keyword string
|
||||
}) {
|
||||
node, err := findHTTPDNSNodeMap(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cluster, err := findHTTPDNSClusterMap(this.Parent(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["currentCluster"] = maps.Map{"id": params.ClusterId, "name": "Mock Cluster"}
|
||||
this.Data["currentCluster"] = cluster
|
||||
this.Data["node"] = node
|
||||
this.Data["dayFrom"] = params.DayFrom
|
||||
this.Data["dayTo"] = params.DayTo
|
||||
this.Data["level"] = params.Level
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
this.Data["dayFrom"] = ""
|
||||
this.Data["dayTo"] = ""
|
||||
this.Data["keyword"] = ""
|
||||
this.Data["level"] = ""
|
||||
this.Data["logs"] = []maps.Map{}
|
||||
day := strings.TrimSpace(params.DayFrom)
|
||||
if len(day) == 0 {
|
||||
day = strings.TrimSpace(params.DayTo)
|
||||
}
|
||||
|
||||
resp, err := this.RPC().HTTPDNSRuntimeLogRPC().ListHTTPDNSRuntimeLogs(this.AdminContext(), &pb.ListHTTPDNSRuntimeLogsRequest{
|
||||
Day: day,
|
||||
ClusterId: params.ClusterId,
|
||||
NodeId: params.NodeId,
|
||||
Level: strings.TrimSpace(params.Level),
|
||||
Keyword: strings.TrimSpace(params.Keyword),
|
||||
Offset: 0,
|
||||
Size: 100,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
logs := make([]maps.Map, 0, len(resp.GetLogs()))
|
||||
for _, item := range resp.GetLogs() {
|
||||
logs = append(logs, maps.Map{
|
||||
"level": item.GetLevel(),
|
||||
"tag": item.GetType(),
|
||||
"description": item.GetDescription(),
|
||||
"createdAt": item.GetCreatedAt(),
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", item.GetCreatedAt()),
|
||||
"count": item.GetCount(),
|
||||
})
|
||||
}
|
||||
this.Data["logs"] = logs
|
||||
this.Data["page"] = ""
|
||||
this.Data["node"] = maps.Map{"id": params.NodeId, "name": "Mock Node"}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func findHTTPDNSClusterMap(parent *actionutils.ParentAction, clusterID int64) (maps.Map, error) {
|
||||
resp, err := parent.RPC().HTTPDNSClusterRPC().FindHTTPDNSCluster(parent.AdminContext(), &pb.FindHTTPDNSClusterRequest{
|
||||
ClusterId: clusterID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.GetCluster() == nil {
|
||||
return maps.Map{
|
||||
"id": clusterID,
|
||||
"name": "",
|
||||
"installDir": "/opt/edge-httpdns",
|
||||
}, nil
|
||||
}
|
||||
|
||||
cluster := resp.GetCluster()
|
||||
installDir := strings.TrimSpace(cluster.GetInstallDir())
|
||||
if len(installDir) == 0 {
|
||||
installDir = "/opt/edge-httpdns"
|
||||
}
|
||||
return maps.Map{
|
||||
"id": cluster.GetId(),
|
||||
"name": cluster.GetName(),
|
||||
"installDir": installDir,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func findHTTPDNSNodeMap(parent *actionutils.ParentAction, nodeID int64) (maps.Map, error) {
|
||||
resp, err := parent.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(parent.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: nodeID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.GetNode() == nil {
|
||||
return maps.Map{}, nil
|
||||
}
|
||||
|
||||
node := resp.GetNode()
|
||||
statusMap := decodeNodeStatus(node.GetStatusJSON())
|
||||
installStatusMap := decodeInstallStatus(node.GetInstallStatusJSON())
|
||||
|
||||
var ipAddresses = []maps.Map{}
|
||||
if installStatusMap.Has("ipAddresses") {
|
||||
for _, addr := range installStatusMap.GetSlice("ipAddresses") {
|
||||
if addrMap, ok := addr.(map[string]interface{}); ok {
|
||||
ipAddresses = append(ipAddresses, maps.Map(addrMap))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ip := node.GetName()
|
||||
if savedIP := strings.TrimSpace(installStatusMap.GetString("ipAddr")); len(savedIP) > 0 {
|
||||
ip = savedIP
|
||||
} else if hostIP := strings.TrimSpace(statusMap.GetString("hostIP")); len(hostIP) > 0 {
|
||||
ip = hostIP
|
||||
}
|
||||
ipAddresses = append(ipAddresses, maps.Map{
|
||||
"id": node.GetId(),
|
||||
"name": "Public IP",
|
||||
"ip": ip,
|
||||
"canAccess": true,
|
||||
"isOn": node.GetIsOn(),
|
||||
"isUp": node.GetIsUp(),
|
||||
})
|
||||
}
|
||||
|
||||
installDir := strings.TrimSpace(node.GetInstallDir())
|
||||
if len(installDir) == 0 {
|
||||
installDir = "/opt/edge-httpdns"
|
||||
}
|
||||
|
||||
clusterMap, err := findHTTPDNSClusterMap(parent, node.GetClusterId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构造 node.login 用于 index.html 展示 SSH 信息
|
||||
var loginMap maps.Map = nil
|
||||
sshInfo := installStatusMap.GetMap("ssh")
|
||||
if sshInfo != nil {
|
||||
grantId := sshInfo.GetInt64("grantId")
|
||||
var grantMap maps.Map = nil
|
||||
if grantId > 0 {
|
||||
grantResp, grantErr := parent.RPC().NodeGrantRPC().FindEnabledNodeGrant(parent.AdminContext(), &pb.FindEnabledNodeGrantRequest{
|
||||
NodeGrantId: grantId,
|
||||
})
|
||||
if grantErr == nil && grantResp.GetNodeGrant() != nil {
|
||||
g := grantResp.GetNodeGrant()
|
||||
grantMap = maps.Map{
|
||||
"id": g.Id,
|
||||
"name": g.Name,
|
||||
"methodName": g.Method,
|
||||
"username": g.Username,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loginMap = maps.Map{
|
||||
"params": maps.Map{
|
||||
"host": sshInfo.GetString("host"),
|
||||
"port": sshInfo.GetInt("port"),
|
||||
},
|
||||
"grant": grantMap,
|
||||
}
|
||||
}
|
||||
|
||||
return maps.Map{
|
||||
"id": node.GetId(),
|
||||
"clusterId": node.GetClusterId(),
|
||||
"name": node.GetName(),
|
||||
"isOn": node.GetIsOn(),
|
||||
"isUp": node.GetIsUp(),
|
||||
"isInstalled": node.GetIsInstalled(),
|
||||
"isActive": node.GetIsActive(),
|
||||
"uniqueId": node.GetUniqueId(),
|
||||
"secret": node.GetSecret(),
|
||||
"installDir": installDir,
|
||||
"status": statusMap,
|
||||
"installStatus": installStatusMap,
|
||||
"cluster": clusterMap,
|
||||
"login": loginMap,
|
||||
"apiNodeAddrs": []string{},
|
||||
"ipAddresses": ipAddresses,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeNodeStatus(raw []byte) maps.Map {
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
if len(raw) > 0 {
|
||||
_ = json.Unmarshal(raw, status)
|
||||
}
|
||||
cpuText := fmt.Sprintf("%.2f%%", status.CPUUsage*100)
|
||||
memText := fmt.Sprintf("%.2f%%", status.MemoryUsage*100)
|
||||
|
||||
return maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"hostIP": status.HostIP,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": cpuText,
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": memText,
|
||||
"load1m": status.Load1m,
|
||||
"load5m": status.Load5m,
|
||||
"load15m": status.Load15m,
|
||||
"buildVersion": status.BuildVersion,
|
||||
"cpuPhysicalCount": status.CPUPhysicalCount,
|
||||
"cpuLogicalCount": status.CPULogicalCount,
|
||||
"exePath": status.ExePath,
|
||||
"apiSuccessPercent": status.APISuccessPercent,
|
||||
"apiAvgCostSeconds": status.APIAvgCostSeconds,
|
||||
}
|
||||
}
|
||||
|
||||
func decodeInstallStatus(raw []byte) maps.Map {
|
||||
result := maps.Map{
|
||||
"isRunning": false,
|
||||
"isFinished": true,
|
||||
"isOk": true,
|
||||
"error": "",
|
||||
"errorCode": "",
|
||||
}
|
||||
if len(raw) == 0 {
|
||||
return result
|
||||
}
|
||||
|
||||
_ = json.Unmarshal(raw, &result)
|
||||
return result
|
||||
}
|
||||
@@ -1,13 +1,41 @@
|
||||
package node
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type StartAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StartAction) RunPost(params struct{ NodeId int64 }) {
|
||||
func (this *StartAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := resp.GetNode()
|
||||
if node == nil {
|
||||
this.Fail("节点不存在")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNodeStatus(this.AdminContext(), &pb.UpdateHTTPDNSNodeStatusRequest{
|
||||
NodeId: params.NodeId,
|
||||
IsUp: true,
|
||||
IsInstalled: node.GetIsInstalled(),
|
||||
IsActive: true,
|
||||
StatusJSON: node.GetStatusJSON(),
|
||||
InstallStatusJSON: node.GetInstallStatusJSON(),
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type StatusAction struct {
|
||||
@@ -14,14 +14,28 @@ func (this *StatusAction) Init() {
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunPost(params struct{ NodeId int64 }) {
|
||||
this.Data["installStatus"] = maps.Map{
|
||||
"isRunning": false,
|
||||
"isFinished": true,
|
||||
"isOk": true,
|
||||
"error": "",
|
||||
"errorCode": "",
|
||||
func (this *StatusAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["isInstalled"] = true
|
||||
if resp.GetNode() == nil {
|
||||
this.Fail("节点不存在")
|
||||
return
|
||||
}
|
||||
|
||||
nodeMap, err := findHTTPDNSNodeMap(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["installStatus"] = nodeMap.GetMap("installStatus")
|
||||
this.Data["isInstalled"] = nodeMap.GetBool("isInstalled")
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -1,13 +1,41 @@
|
||||
package node
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type StopAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StopAction) RunPost(params struct{ NodeId int64 }) {
|
||||
func (this *StopAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := resp.GetNode()
|
||||
if node == nil {
|
||||
this.Fail("节点不存在")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNodeStatus(this.AdminContext(), &pb.UpdateHTTPDNSNodeStatusRequest{
|
||||
NodeId: params.NodeId,
|
||||
IsUp: node.GetIsUp(),
|
||||
IsInstalled: node.GetIsInstalled(),
|
||||
IsActive: false,
|
||||
StatusJSON: node.GetStatusJSON(),
|
||||
InstallStatusJSON: node.GetInstallStatusJSON(),
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
package node
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -14,28 +21,210 @@ func (this *UpdateAction) Init() {
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunGet(params struct{ ClusterId int64; NodeId int64 }) {
|
||||
func (this *UpdateAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
node, err := findHTTPDNSNodeMap(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cluster, err := findHTTPDNSClusterMap(this.Parent(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["currentCluster"] = maps.Map{"id": params.ClusterId, "name": "Mock Cluster"}
|
||||
|
||||
this.Data["clusters"] = []maps.Map{{"id": params.ClusterId, "name": "Mock Cluster"}}
|
||||
this.Data["loginId"] = 0
|
||||
this.Data["sshHost"] = "192.168.1.100"
|
||||
this.Data["sshPort"] = 22
|
||||
this.Data["grant"] = nil
|
||||
this.Data["currentCluster"] = cluster
|
||||
this.Data["clusters"] = []maps.Map{cluster}
|
||||
this.Data["apiNodeAddrs"] = []string{}
|
||||
this.Data["node"] = node
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": params.NodeId,
|
||||
"name": "Mock Node",
|
||||
"isOn": true,
|
||||
"ipAddresses": []maps.Map{},
|
||||
sshHost := ""
|
||||
sshPort := 22
|
||||
ipAddresses := []maps.Map{}
|
||||
var grantId int64
|
||||
this.Data["grant"] = nil
|
||||
|
||||
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err == nil && resp.GetNode() != nil {
|
||||
if len(resp.GetNode().GetInstallStatusJSON()) > 0 {
|
||||
installStatus := maps.Map{}
|
||||
_ = json.Unmarshal(resp.GetNode().GetInstallStatusJSON(), &installStatus)
|
||||
sshInfo := installStatus.GetMap("ssh")
|
||||
if sshInfo != nil {
|
||||
if h := strings.TrimSpace(sshInfo.GetString("host")); len(h) > 0 {
|
||||
sshHost = h
|
||||
}
|
||||
if p := sshInfo.GetInt("port"); p > 0 {
|
||||
sshPort = p
|
||||
}
|
||||
grantId = sshInfo.GetInt64("grantId")
|
||||
}
|
||||
|
||||
if installStatus.Has("ipAddresses") {
|
||||
for _, addr := range installStatus.GetSlice("ipAddresses") {
|
||||
if addrMap, ok := addr.(map[string]interface{}); ok {
|
||||
ipAddresses = append(ipAddresses, maps.Map(addrMap))
|
||||
}
|
||||
}
|
||||
} else if ip := strings.TrimSpace(installStatus.GetString("ipAddr")); len(ip) > 0 {
|
||||
ipAddresses = append(ipAddresses, maps.Map{
|
||||
"ip": ip,
|
||||
"name": "",
|
||||
"canAccess": true,
|
||||
"isOn": true,
|
||||
"isUp": true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["sshHost"] = sshHost
|
||||
this.Data["sshPort"] = sshPort
|
||||
this.Data["ipAddresses"] = ipAddresses
|
||||
|
||||
if grantId > 0 {
|
||||
grantResp, grantErr := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{
|
||||
NodeGrantId: grantId,
|
||||
})
|
||||
if grantErr == nil && grantResp.GetNodeGrant() != nil {
|
||||
g := grantResp.GetNodeGrant()
|
||||
this.Data["grant"] = maps.Map{
|
||||
"id": g.Id,
|
||||
"name": g.Name,
|
||||
"methodName": g.Method,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct{ NodeId int64 }) {
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
Name string
|
||||
ClusterId int64
|
||||
IsOn bool
|
||||
SshHost string
|
||||
SshPort int
|
||||
GrantId int64
|
||||
IpAddressesJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Name = strings.TrimSpace(params.Name)
|
||||
params.Must.Field("name", params.Name).Require("请输入节点名称")
|
||||
|
||||
params.SshHost = strings.TrimSpace(params.SshHost)
|
||||
hasSSHUpdate := len(params.SshHost) > 0 || params.SshPort > 0 || params.GrantId > 0
|
||||
if hasSSHUpdate {
|
||||
if len(params.SshHost) == 0 {
|
||||
this.Fail("请输入 SSH 主机地址")
|
||||
}
|
||||
if params.SshPort <= 0 || params.SshPort > 65535 {
|
||||
this.Fail("SSH 端口范围必须在 1-65535 之间")
|
||||
}
|
||||
if params.GrantId <= 0 {
|
||||
this.Fail("请选择 SSH 登录认证")
|
||||
}
|
||||
|
||||
if regexp.MustCompile(`^\d+\.\d+\.\d+\.\d+$`).MatchString(params.SshHost) && net.ParseIP(params.SshHost) == nil {
|
||||
this.Fail("SSH 主机地址格式错误")
|
||||
}
|
||||
}
|
||||
|
||||
ipAddresses := []maps.Map{}
|
||||
if len(params.IpAddressesJSON) > 0 {
|
||||
err := json.Unmarshal(params.IpAddressesJSON, &ipAddresses)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, addr := range ipAddresses {
|
||||
ip := addr.GetString("ip")
|
||||
if net.ParseIP(ip) == nil {
|
||||
this.Fail("IP地址格式错误: " + ip)
|
||||
}
|
||||
}
|
||||
|
||||
needUpdateInstallStatus := hasSSHUpdate || len(ipAddresses) > 0
|
||||
|
||||
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.GetNode() == nil {
|
||||
this.Fail("节点不存在")
|
||||
return
|
||||
}
|
||||
node := resp.GetNode()
|
||||
|
||||
installDir := strings.TrimSpace(node.GetInstallDir())
|
||||
if len(installDir) == 0 {
|
||||
installDir = "/opt/edge-httpdns"
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNode(this.AdminContext(), &pb.UpdateHTTPDNSNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
Name: params.Name,
|
||||
InstallDir: installDir,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if needUpdateInstallStatus {
|
||||
installStatus := maps.Map{
|
||||
"isRunning": false,
|
||||
"isFinished": true,
|
||||
"isOk": node.GetIsInstalled(),
|
||||
"error": "",
|
||||
"errorCode": "",
|
||||
}
|
||||
if len(node.GetInstallStatusJSON()) > 0 {
|
||||
_ = json.Unmarshal(node.GetInstallStatusJSON(), &installStatus)
|
||||
}
|
||||
if hasSSHUpdate {
|
||||
installStatus["ssh"] = maps.Map{
|
||||
"host": params.SshHost,
|
||||
"port": params.SshPort,
|
||||
"grantId": params.GrantId,
|
||||
}
|
||||
}
|
||||
if len(ipAddresses) > 0 {
|
||||
installStatus["ipAddresses"] = ipAddresses
|
||||
} else {
|
||||
delete(installStatus, "ipAddresses")
|
||||
delete(installStatus, "ipAddr") // Cleanup legacy
|
||||
}
|
||||
|
||||
installStatusJSON, _ := json.Marshal(installStatus)
|
||||
_, err = this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNodeStatus(this.AdminContext(), &pb.UpdateHTTPDNSNodeStatusRequest{
|
||||
NodeId: params.NodeId,
|
||||
IsUp: node.GetIsUp(),
|
||||
IsInstalled: node.GetIsInstalled(),
|
||||
IsActive: node.GetIsActive(),
|
||||
StatusJSON: node.GetStatusJSON(),
|
||||
InstallStatusJSON: installStatusJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -1,13 +1,58 @@
|
||||
package node
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type UpdateInstallStatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateInstallStatusAction) RunPost(params struct{ NodeId int64 }) {
|
||||
func (this *UpdateInstallStatusAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
IsInstalled bool
|
||||
}) {
|
||||
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := resp.GetNode()
|
||||
if node == nil {
|
||||
this.Fail("节点不存在")
|
||||
return
|
||||
}
|
||||
|
||||
installStatus := map[string]interface{}{}
|
||||
if len(node.GetInstallStatusJSON()) > 0 {
|
||||
_ = json.Unmarshal(node.GetInstallStatusJSON(), &installStatus)
|
||||
}
|
||||
installStatus["isRunning"] = false
|
||||
installStatus["isFinished"] = true
|
||||
installStatus["isOk"] = params.IsInstalled
|
||||
installStatus["error"] = ""
|
||||
installStatus["errorCode"] = ""
|
||||
installStatus["updatedAt"] = time.Now().Unix()
|
||||
|
||||
installStatusJSON, _ := json.Marshal(installStatus)
|
||||
|
||||
_, err = this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNodeStatus(this.AdminContext(), &pb.UpdateHTTPDNSNodeStatusRequest{
|
||||
NodeId: params.NodeId,
|
||||
IsUp: node.GetIsUp(),
|
||||
IsInstalled: params.IsInstalled,
|
||||
IsActive: node.GetIsActive(),
|
||||
StatusJSON: node.GetStatusJSON(),
|
||||
InstallStatusJSON: installStatusJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/policies"
|
||||
"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"
|
||||
@@ -27,80 +27,79 @@ func (this *ClusterSettingsAction) RunGet(params struct {
|
||||
Section string
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
cluster := pickCluster(params.ClusterId)
|
||||
settings := loadClusterSettings(cluster)
|
||||
cluster["name"] = settings.GetString("name")
|
||||
|
||||
// 构建顶部 tabbar
|
||||
cluster, err := findClusterMap(this.Parent(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
httpdnsutils.AddClusterTabbar(this.Parent(), cluster.GetString("name"), params.ClusterId, "setting")
|
||||
|
||||
// 当前选中的 section
|
||||
section := params.Section
|
||||
section := strings.TrimSpace(params.Section)
|
||||
if len(section) == 0 {
|
||||
section = "basic"
|
||||
}
|
||||
this.Data["activeSection"] = section
|
||||
|
||||
// 左侧菜单
|
||||
settings := maps.Map{
|
||||
"name": cluster.GetString("name"),
|
||||
"gatewayDomain": cluster.GetString("gatewayDomain"),
|
||||
"cacheTtl": cluster.GetInt("defaultTTL"),
|
||||
"fallbackTimeout": cluster.GetInt("fallbackTimeout"),
|
||||
"installDir": cluster.GetString("installDir"),
|
||||
"isOn": cluster.GetBool("isOn"),
|
||||
"isDefaultCluster": cluster.GetBool("isDefault"),
|
||||
}
|
||||
if settings.GetInt("cacheTtl") <= 0 {
|
||||
settings["cacheTtl"] = 30
|
||||
}
|
||||
if settings.GetInt("fallbackTimeout") <= 0 {
|
||||
settings["fallbackTimeout"] = 300
|
||||
}
|
||||
if len(settings.GetString("installDir")) == 0 {
|
||||
settings["installDir"] = "/opt/edge-httpdns"
|
||||
}
|
||||
|
||||
listenAddresses := []*serverconfigs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: serverconfigs.ProtocolHTTPS,
|
||||
Host: "",
|
||||
PortRange: "443",
|
||||
},
|
||||
}
|
||||
sslPolicy := &sslconfigs.SSLPolicy{
|
||||
IsOn: true,
|
||||
MinVersion: "TLS 1.1",
|
||||
}
|
||||
|
||||
if rawTLS := strings.TrimSpace(cluster.GetString("tlsPolicyJSON")); len(rawTLS) > 0 {
|
||||
tlsConfig := maps.Map{}
|
||||
if err := json.Unmarshal([]byte(rawTLS), &tlsConfig); err == nil {
|
||||
if listenRaw := tlsConfig.Get("listen"); listenRaw != nil {
|
||||
if data, err := json.Marshal(listenRaw); err == nil {
|
||||
_ = json.Unmarshal(data, &listenAddresses)
|
||||
}
|
||||
}
|
||||
if sslRaw := tlsConfig.Get("sslPolicy"); sslRaw != nil {
|
||||
if data, err := json.Marshal(sslRaw); err == nil {
|
||||
_ = json.Unmarshal(data, sslPolicy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["activeSection"] = section
|
||||
cid := strconv.FormatInt(params.ClusterId, 10)
|
||||
this.Data["leftMenuItems"] = []map[string]interface{}{
|
||||
{"name": "基础设置", "url": "/httpdns/clusters/cluster/settings?clusterId=" + cid + "§ion=basic", "isActive": section == "basic"},
|
||||
{"name": "端口设置", "url": "/httpdns/clusters/cluster/settings?clusterId=" + cid + "§ion=tls", "isActive": section == "tls"},
|
||||
{"name": "TLS", "url": "/httpdns/clusters/cluster/settings?clusterId=" + cid + "§ion=tls", "isActive": section == "tls"},
|
||||
}
|
||||
|
||||
settings["isDefaultCluster"] = (policies.LoadDefaultClusterID() == cluster.GetInt64("id"))
|
||||
|
||||
this.Data["cluster"] = cluster
|
||||
// 构造前端需要的 tlsConfig 格式
|
||||
var listenAddresses []*serverconfigs.NetworkAddressConfig
|
||||
listenAddrsRaw := settings.GetString("listenAddrsJSON")
|
||||
if len(listenAddrsRaw) > 0 {
|
||||
_ = json.Unmarshal([]byte(listenAddrsRaw), &listenAddresses)
|
||||
} else {
|
||||
// 默认 443 端口
|
||||
listenAddresses = []*serverconfigs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: serverconfigs.ProtocolHTTPS,
|
||||
Host: "",
|
||||
PortRange: "443",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 构造前端需要的 SSLPolicy
|
||||
var sslPolicy *sslconfigs.SSLPolicy
|
||||
originCertPem := settings.GetString("originCertPem")
|
||||
originKeyPem := settings.GetString("originKeyPem")
|
||||
if len(originCertPem) > 0 && len(originKeyPem) > 0 {
|
||||
sslPolicy = &sslconfigs.SSLPolicy{
|
||||
IsOn: true,
|
||||
MinVersion: settings.GetString("tlsMinVersion"),
|
||||
CipherSuitesIsOn: settings.GetBool("tlsCipherSuitesOn"),
|
||||
OCSPIsOn: settings.GetBool("tlsOcspOn"),
|
||||
ClientAuthType: int(settings.GetInt32("tlsClientAuthType")),
|
||||
Certs: []*sslconfigs.SSLCertConfig{
|
||||
{
|
||||
IsOn: true,
|
||||
CertData: []byte(originCertPem),
|
||||
KeyData: []byte(originKeyPem),
|
||||
},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
sslPolicy = &sslconfigs.SSLPolicy{
|
||||
IsOn: true,
|
||||
MinVersion: "TLS 1.1",
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["settings"] = settings
|
||||
this.Data["tlsConfig"] = maps.Map{
|
||||
"isOn": true,
|
||||
"listen": listenAddresses,
|
||||
"sslPolicy": sslPolicy,
|
||||
}
|
||||
|
||||
this.Data["cluster"] = cluster
|
||||
this.Data["settings"] = settings
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -120,88 +119,80 @@ func (this *ClusterSettingsAction) RunPost(params struct {
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.Field("clusterId", params.ClusterId).Gt(0, "please select cluster")
|
||||
params.Must.Field("name", params.Name).Require("please input cluster name")
|
||||
params.Must.Field("gatewayDomain", params.GatewayDomain).Require("please input service domain")
|
||||
params.Must.Field("cacheTtl", params.CacheTtl).Gt(0, "cache ttl should be greater than 0")
|
||||
params.Must.Field("fallbackTimeout", params.FallbackTimeout).Gt(0, "fallback timeout should be greater than 0")
|
||||
params.Must.Field("installDir", params.InstallDir).Require("please input install dir")
|
||||
params.Name = strings.TrimSpace(params.Name)
|
||||
params.GatewayDomain = strings.TrimSpace(params.GatewayDomain)
|
||||
params.InstallDir = strings.TrimSpace(params.InstallDir)
|
||||
|
||||
params.Must.Field("clusterId", params.ClusterId).Gt(0, "请选择集群")
|
||||
params.Must.Field("name", params.Name).Require("请输入集群名称")
|
||||
params.Must.Field("gatewayDomain", params.GatewayDomain).Require("请输入服务域名")
|
||||
|
||||
if params.CacheTtl <= 0 {
|
||||
params.CacheTtl = 30
|
||||
}
|
||||
if params.FallbackTimeout <= 0 {
|
||||
params.FallbackTimeout = 300
|
||||
}
|
||||
if len(params.InstallDir) == 0 {
|
||||
params.InstallDir = "/opt/edge-httpdns"
|
||||
}
|
||||
if params.IsDefaultCluster && !params.IsOn {
|
||||
this.Fail("默认集群必须保持启用状态")
|
||||
return
|
||||
}
|
||||
|
||||
cluster := pickCluster(params.ClusterId)
|
||||
settings := loadClusterSettings(cluster)
|
||||
settings["name"] = strings.TrimSpace(params.Name)
|
||||
settings["gatewayDomain"] = strings.TrimSpace(params.GatewayDomain)
|
||||
settings["cacheTtl"] = int(params.CacheTtl)
|
||||
settings["fallbackTimeout"] = int(params.FallbackTimeout)
|
||||
settings["installDir"] = strings.TrimSpace(params.InstallDir)
|
||||
settings["isOn"] = params.IsOn
|
||||
// 处理地址
|
||||
var addresses = []*serverconfigs.NetworkAddressConfig{}
|
||||
if len(params.Addresses) > 0 {
|
||||
err := json.Unmarshal(params.Addresses, &addresses)
|
||||
if err != nil {
|
||||
this.Fail("端口地址解析失败:" + err.Error())
|
||||
}
|
||||
|
||||
addressesJSON, _ := json.Marshal(addresses)
|
||||
settings["listenAddrsJSON"] = string(addressesJSON)
|
||||
cluster, err := findClusterMap(this.Parent(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 处理 SSL 配置
|
||||
var originCertPem = ""
|
||||
var originKeyPem = ""
|
||||
var tlsMinVersion = "TLS 1.1"
|
||||
var tlsCipherSuitesOn = false
|
||||
var tlsOcspOn = false
|
||||
var tlsClientAuthType = sslconfigs.SSLClientAuthType(0)
|
||||
tlsConfig := maps.Map{}
|
||||
if rawTLS := strings.TrimSpace(cluster.GetString("tlsPolicyJSON")); len(rawTLS) > 0 {
|
||||
_ = json.Unmarshal([]byte(rawTLS), &tlsConfig)
|
||||
}
|
||||
|
||||
if len(params.Addresses) > 0 {
|
||||
var addresses []*serverconfigs.NetworkAddressConfig
|
||||
if err := json.Unmarshal(params.Addresses, &addresses); err != nil {
|
||||
this.Fail("监听端口配置格式不正确")
|
||||
return
|
||||
}
|
||||
tlsConfig["listen"] = addresses
|
||||
}
|
||||
|
||||
if len(params.SslPolicyJSON) > 0 {
|
||||
sslPolicy := &sslconfigs.SSLPolicy{}
|
||||
err := json.Unmarshal(params.SslPolicyJSON, sslPolicy)
|
||||
if err == nil {
|
||||
tlsMinVersion = sslPolicy.MinVersion
|
||||
tlsCipherSuitesOn = sslPolicy.CipherSuitesIsOn
|
||||
tlsOcspOn = sslPolicy.OCSPIsOn
|
||||
tlsClientAuthType = sslconfigs.SSLClientAuthType(sslPolicy.ClientAuthType)
|
||||
if err := json.Unmarshal(params.SslPolicyJSON, sslPolicy); err != nil {
|
||||
this.Fail("TLS 配置格式不正确")
|
||||
return
|
||||
}
|
||||
tlsConfig["sslPolicy"] = sslPolicy
|
||||
}
|
||||
|
||||
if len(sslPolicy.Certs) > 0 {
|
||||
cert := sslPolicy.Certs[0]
|
||||
originCertPem = string(cert.CertData)
|
||||
originKeyPem = string(cert.KeyData)
|
||||
}
|
||||
var tlsPolicyJSON []byte
|
||||
if len(tlsConfig) > 0 {
|
||||
tlsPolicyJSON, err = json.Marshal(tlsConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(originCertPem) == 0 || len(originKeyPem) == 0 {
|
||||
this.Fail("请上传或选择证书")
|
||||
}
|
||||
|
||||
settings["originHttps"] = true
|
||||
settings["originCertPem"] = originCertPem
|
||||
settings["originKeyPem"] = originKeyPem
|
||||
if len(tlsMinVersion) == 0 {
|
||||
tlsMinVersion = "TLS 1.1"
|
||||
}
|
||||
settings["tlsMinVersion"] = tlsMinVersion
|
||||
settings["tlsCipherSuitesOn"] = tlsCipherSuitesOn
|
||||
settings["tlsOcspOn"] = tlsOcspOn
|
||||
settings["tlsClientAuthType"] = int(tlsClientAuthType)
|
||||
settings["lastModifiedAt"] = nowDateTime()
|
||||
settings["certUpdatedAt"] = nowDateTime()
|
||||
|
||||
saveClusterSettings(params.ClusterId, settings)
|
||||
|
||||
currentDefaultClusterId := policies.LoadDefaultClusterID()
|
||||
if params.IsDefaultCluster {
|
||||
policies.SaveDefaultClusterID(params.ClusterId)
|
||||
} else if currentDefaultClusterId == params.ClusterId {
|
||||
policies.SaveDefaultClusterID(0)
|
||||
_, err = this.RPC().HTTPDNSClusterRPC().UpdateHTTPDNSCluster(this.AdminContext(), &pb.UpdateHTTPDNSClusterRequest{
|
||||
ClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
ServiceDomain: params.GatewayDomain,
|
||||
DefaultTTL: params.CacheTtl,
|
||||
FallbackTimeoutMs: params.FallbackTimeout,
|
||||
InstallDir: params.InstallDir,
|
||||
TlsPolicyJSON: tlsPolicyJSON,
|
||||
IsOn: params.IsOn,
|
||||
IsDefault: params.IsDefaultCluster,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
var clusterSettingsStore = struct {
|
||||
sync.RWMutex
|
||||
data map[int64]maps.Map
|
||||
}{
|
||||
data: map[int64]maps.Map{},
|
||||
}
|
||||
|
||||
func defaultClusterSettings(cluster maps.Map) maps.Map {
|
||||
installDir := strings.TrimSpace(cluster.GetString("installDir"))
|
||||
if len(installDir) == 0 {
|
||||
installDir = "/opt/edge-httpdns"
|
||||
}
|
||||
|
||||
return maps.Map{
|
||||
"name": cluster.GetString("name"),
|
||||
"gatewayDomain": strings.TrimSpace(cluster.GetString("gatewayDomain")),
|
||||
"cacheTtl": cluster.GetInt("cacheTtl"),
|
||||
"fallbackTimeout": cluster.GetInt("fallbackTimeout"),
|
||||
"installDir": installDir,
|
||||
"isOn": cluster.GetBool("isOn"),
|
||||
"originHttps": true,
|
||||
"originCertPem": "",
|
||||
"originKeyPem": "",
|
||||
"tlsMinVersion": "TLS 1.1",
|
||||
"tlsCipherSuitesOn": false,
|
||||
"tlsOcspOn": false,
|
||||
"tlsClientAuthType": 0,
|
||||
"certUpdatedAt": "",
|
||||
"lastModifiedAt": "",
|
||||
}
|
||||
}
|
||||
|
||||
func cloneClusterSettings(settings maps.Map) maps.Map {
|
||||
return maps.Map{
|
||||
"name": settings.GetString("name"),
|
||||
"gatewayDomain": settings.GetString("gatewayDomain"),
|
||||
"cacheTtl": settings.GetInt("cacheTtl"),
|
||||
"fallbackTimeout": settings.GetInt("fallbackTimeout"),
|
||||
"installDir": settings.GetString("installDir"),
|
||||
"isOn": settings.GetBool("isOn"),
|
||||
"originHttps": true,
|
||||
"originCertPem": settings.GetString("originCertPem"),
|
||||
"originKeyPem": settings.GetString("originKeyPem"),
|
||||
"tlsMinVersion": settings.GetString("tlsMinVersion"),
|
||||
"tlsCipherSuitesOn": settings.GetBool("tlsCipherSuitesOn"),
|
||||
"tlsOcspOn": settings.GetBool("tlsOcspOn"),
|
||||
"tlsClientAuthType": settings.GetInt("tlsClientAuthType"),
|
||||
"certUpdatedAt": settings.GetString("certUpdatedAt"),
|
||||
"lastModifiedAt": settings.GetString("lastModifiedAt"),
|
||||
}
|
||||
}
|
||||
|
||||
func loadClusterSettings(cluster maps.Map) maps.Map {
|
||||
clusterId := cluster.GetInt64("id")
|
||||
|
||||
clusterSettingsStore.RLock()
|
||||
settings, ok := clusterSettingsStore.data[clusterId]
|
||||
clusterSettingsStore.RUnlock()
|
||||
if ok {
|
||||
if len(settings.GetString("tlsMinVersion")) == 0 {
|
||||
settings["tlsMinVersion"] = "TLS 1.1"
|
||||
}
|
||||
return cloneClusterSettings(settings)
|
||||
}
|
||||
|
||||
settings = defaultClusterSettings(cluster)
|
||||
saveClusterSettings(clusterId, settings)
|
||||
return cloneClusterSettings(settings)
|
||||
}
|
||||
|
||||
func saveClusterSettings(clusterId int64, settings maps.Map) {
|
||||
clusterSettingsStore.Lock()
|
||||
clusterSettingsStore.data[clusterId] = cloneClusterSettings(settings)
|
||||
clusterSettingsStore.Unlock()
|
||||
}
|
||||
|
||||
func applyClusterSettingsOverrides(cluster maps.Map) {
|
||||
clusterId := cluster.GetInt64("id")
|
||||
if clusterId <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
clusterSettingsStore.RLock()
|
||||
settings, ok := clusterSettingsStore.data[clusterId]
|
||||
clusterSettingsStore.RUnlock()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
cluster["name"] = settings.GetString("name")
|
||||
cluster["gatewayDomain"] = settings.GetString("gatewayDomain")
|
||||
cluster["cacheTtl"] = settings.GetInt("cacheTtl")
|
||||
cluster["fallbackTimeout"] = settings.GetInt("fallbackTimeout")
|
||||
cluster["installDir"] = settings.GetString("installDir")
|
||||
cluster["isOn"] = settings.GetBool("isOn")
|
||||
}
|
||||
|
||||
func nowDateTime() string {
|
||||
return time.Now().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreateAction struct {
|
||||
@@ -17,3 +21,48 @@ func (this *CreateAction) RunGet(params struct{}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunPost(params struct {
|
||||
Name string
|
||||
GatewayDomain string
|
||||
CacheTtl int32
|
||||
FallbackTimeout int32
|
||||
InstallDir string
|
||||
IsOn bool
|
||||
IsDefault bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Name = strings.TrimSpace(params.Name)
|
||||
params.GatewayDomain = strings.TrimSpace(params.GatewayDomain)
|
||||
params.InstallDir = strings.TrimSpace(params.InstallDir)
|
||||
if len(params.InstallDir) == 0 {
|
||||
params.InstallDir = "/opt/edge-httpdns"
|
||||
}
|
||||
if params.CacheTtl <= 0 {
|
||||
params.CacheTtl = 30
|
||||
}
|
||||
if params.FallbackTimeout <= 0 {
|
||||
params.FallbackTimeout = 300
|
||||
}
|
||||
|
||||
params.Must.Field("name", params.Name).Require("请输入集群名称")
|
||||
params.Must.Field("gatewayDomain", params.GatewayDomain).Require("请输入服务域名")
|
||||
|
||||
resp, err := this.RPC().HTTPDNSClusterRPC().CreateHTTPDNSCluster(this.AdminContext(), &pb.CreateHTTPDNSClusterRequest{
|
||||
Name: params.Name,
|
||||
ServiceDomain: params.GatewayDomain,
|
||||
DefaultTTL: params.CacheTtl,
|
||||
FallbackTimeoutMs: params.FallbackTimeout,
|
||||
InstallDir: params.InstallDir,
|
||||
IsOn: params.IsOn,
|
||||
IsDefault: params.IsDefault,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["clusterId"] = resp.GetClusterId()
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreateNodeAction struct {
|
||||
@@ -13,13 +16,18 @@ func (this *CreateNodeAction) Init() {
|
||||
this.Nav("httpdns", "cluster", "createNode")
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) RunGet(params struct{ ClusterId int64 }) {
|
||||
func (this *CreateNodeAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
cluster := pickCluster(params.ClusterId)
|
||||
|
||||
// 构建顶部 tabbar
|
||||
cluster, err := findClusterMap(this.Parent(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
httpdnsutils.AddClusterTabbar(this.Parent(), cluster.GetString("name"), params.ClusterId, "node")
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["cluster"] = cluster
|
||||
this.Show()
|
||||
@@ -28,6 +36,28 @@ func (this *CreateNodeAction) RunGet(params struct{ ClusterId int64 }) {
|
||||
func (this *CreateNodeAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Name string
|
||||
InstallDir string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Name = strings.TrimSpace(params.Name)
|
||||
params.InstallDir = strings.TrimSpace(params.InstallDir)
|
||||
params.Must.Field("clusterId", params.ClusterId).Gt(0, "请选择集群")
|
||||
params.Must.Field("name", params.Name).Require("请输入节点名称")
|
||||
|
||||
if len(params.InstallDir) == 0 {
|
||||
cluster, err := findClusterMap(this.Parent(), params.ClusterId)
|
||||
if err == nil {
|
||||
params.InstallDir = strings.TrimSpace(cluster.GetString("installDir"))
|
||||
}
|
||||
if len(params.InstallDir) == 0 {
|
||||
params.InstallDir = "/opt/edge-httpdns"
|
||||
}
|
||||
}
|
||||
|
||||
if err := createNode(this.Parent(), params.ClusterId, params.Name, params.InstallDir); err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package clusters
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
@@ -17,11 +18,14 @@ func (this *DeleteAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
cluster := pickCluster(params.ClusterId)
|
||||
|
||||
// 构建顶部 tabbar
|
||||
cluster, err := findClusterMap(this.Parent(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
httpdnsutils.AddClusterTabbar(this.Parent(), cluster.GetString("name"), params.ClusterId, "delete")
|
||||
|
||||
this.Data["cluster"] = cluster
|
||||
this.Show()
|
||||
}
|
||||
@@ -29,6 +33,12 @@ func (this *DeleteAction) RunGet(params struct {
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
_ = params.ClusterId
|
||||
_, err := this.RPC().HTTPDNSClusterRPC().DeleteHTTPDNSCluster(this.AdminContext(), &pb.DeleteHTTPDNSClusterRequest{
|
||||
ClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
package clusters
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
)
|
||||
type DeleteNodeAction struct { actionutils.ParentAction }
|
||||
func (this *DeleteNodeAction) RunPost(params struct{ ClusterId int64; NodeId int64 }) { this.Success() }
|
||||
package clusters
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type DeleteNodeAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteNodeAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
if err := deleteNode(this.Parent(), params.NodeId); err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -13,8 +13,27 @@ func (this *IndexAction) Init() {
|
||||
this.Nav("httpdns", "cluster", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Keyword string
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
this.Data["clusters"] = mockClusters()
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
clusters, err := listClusterMaps(this.Parent(), params.Keyword)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["clusters"] = clusters
|
||||
|
||||
hasErrorLogs := false
|
||||
for _, cluster := range clusters {
|
||||
if cluster.GetInt("countAllNodes") > cluster.GetInt("countActiveNodes") {
|
||||
hasErrorLogs = true
|
||||
break
|
||||
}
|
||||
}
|
||||
this.Data["hasErrorLogs"] = hasErrorLogs
|
||||
this.Data["page"] = ""
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func init() {
|
||||
Data("teaSubMenu", "cluster").
|
||||
Prefix("/httpdns/clusters").
|
||||
Get("", new(IndexAction)).
|
||||
Get("/create", new(CreateAction)).
|
||||
GetPost("/create", new(CreateAction)).
|
||||
Get("/cluster", new(ClusterAction)).
|
||||
GetPost("/cluster/settings", new(ClusterSettingsAction)).
|
||||
GetPost("/delete", new(DeleteAction)).
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
package clusters
|
||||
|
||||
import "github.com/iwind/TeaGo/maps"
|
||||
|
||||
func mockClusters() []maps.Map {
|
||||
clusters := []maps.Map{
|
||||
{
|
||||
"id": int64(1),
|
||||
"name": "gateway-cn-hz",
|
||||
"region": "cn-hangzhou",
|
||||
"gatewayDomain": "gw-hz.httpdns.example.com",
|
||||
"installDir": "/opt/edge-httpdns",
|
||||
"countAllNodes": 3,
|
||||
"countActiveNodes": 3,
|
||||
"countApps": 5,
|
||||
"cacheTtl": 30,
|
||||
"fallbackTimeout": 300,
|
||||
"isOn": true,
|
||||
},
|
||||
{
|
||||
"id": int64(2),
|
||||
"name": "gateway-cn-bj",
|
||||
"region": "cn-beijing",
|
||||
"gatewayDomain": "gw-bj.httpdns.example.com",
|
||||
"installDir": "/opt/edge-httpdns",
|
||||
"countAllNodes": 3,
|
||||
"countActiveNodes": 2,
|
||||
"countApps": 2,
|
||||
"cacheTtl": 30,
|
||||
"fallbackTimeout": 300,
|
||||
"isOn": true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, cluster := range clusters {
|
||||
applyClusterSettingsOverrides(cluster)
|
||||
}
|
||||
|
||||
return clusters
|
||||
}
|
||||
|
||||
func pickCluster(clusterId int64) maps.Map {
|
||||
clusters := mockClusters()
|
||||
if clusterId <= 0 {
|
||||
return clusters[0]
|
||||
}
|
||||
for _, c := range clusters {
|
||||
if c.GetInt64("id") == clusterId {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return clusters[0]
|
||||
}
|
||||
|
||||
func mockNodes(clusterId int64, installState int, activeState int, keyword string) []maps.Map {
|
||||
_ = clusterId
|
||||
return []maps.Map{
|
||||
{
|
||||
"id": int64(101),
|
||||
"name": "45.250.184.56",
|
||||
"isInstalled": true,
|
||||
"isOn": true,
|
||||
"isUp": true,
|
||||
"installStatus": maps.Map{
|
||||
"isRunning": false,
|
||||
"isFinished": true,
|
||||
"isOk": true,
|
||||
"error": "",
|
||||
},
|
||||
"status": maps.Map{
|
||||
"isActive": true,
|
||||
"updatedAt": 1700000000,
|
||||
"hostname": "node-01",
|
||||
"cpuUsage": 0.0253,
|
||||
"cpuUsageText": "2.53%",
|
||||
"memUsage": 0.5972,
|
||||
"memUsageText": "59.72%",
|
||||
"load1m": 0.02,
|
||||
},
|
||||
"ipAddresses": []maps.Map{
|
||||
{
|
||||
"id": 1,
|
||||
"name": "",
|
||||
"ip": "45.250.184.56",
|
||||
"canAccess": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": int64(102),
|
||||
"name": "45.250.184.53",
|
||||
"isInstalled": true,
|
||||
"isOn": true,
|
||||
"isUp": true,
|
||||
"installStatus": maps.Map{
|
||||
"isRunning": false,
|
||||
"isFinished": true,
|
||||
"isOk": true,
|
||||
"error": "",
|
||||
},
|
||||
"status": maps.Map{
|
||||
"isActive": true,
|
||||
"updatedAt": 1700000000,
|
||||
"hostname": "node-02",
|
||||
"cpuUsage": 0.0039,
|
||||
"cpuUsageText": "0.39%",
|
||||
"memUsage": 0.0355,
|
||||
"memUsageText": "3.55%",
|
||||
"load1m": 0.0,
|
||||
},
|
||||
"ipAddresses": []maps.Map{
|
||||
{
|
||||
"id": 2,
|
||||
"name": "",
|
||||
"ip": "45.250.184.53",
|
||||
"canAccess": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func mockCerts() []maps.Map {
|
||||
return []maps.Map{
|
||||
{
|
||||
"id": int64(11),
|
||||
"domain": "resolve.edge.example.com",
|
||||
"issuer": "Mock CA",
|
||||
"expiresAt": "2026-12-31 23:59:59",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func listClusterMaps(parent *actionutils.ParentAction, keyword string) ([]maps.Map, error) {
|
||||
resp, err := parent.RPC().HTTPDNSClusterRPC().ListHTTPDNSClusters(parent.AdminContext(), &pb.ListHTTPDNSClustersRequest{
|
||||
Offset: 0,
|
||||
Size: 10_000,
|
||||
Keyword: strings.TrimSpace(keyword),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]maps.Map, 0, len(resp.GetClusters()))
|
||||
for _, cluster := range resp.GetClusters() {
|
||||
nodesResp, err := parent.RPC().HTTPDNSNodeRPC().ListHTTPDNSNodes(parent.AdminContext(), &pb.ListHTTPDNSNodesRequest{
|
||||
ClusterId: cluster.GetId(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
countAllNodes := len(nodesResp.GetNodes())
|
||||
countActiveNodes := 0
|
||||
for _, node := range nodesResp.GetNodes() {
|
||||
if node.GetIsOn() && node.GetIsUp() && node.GetIsActive() {
|
||||
countActiveNodes++
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, maps.Map{
|
||||
"id": cluster.GetId(),
|
||||
"name": cluster.GetName(),
|
||||
"gatewayDomain": cluster.GetServiceDomain(),
|
||||
"defaultTTL": cluster.GetDefaultTTL(),
|
||||
"fallbackTimeout": cluster.GetFallbackTimeoutMs(),
|
||||
"installDir": cluster.GetInstallDir(),
|
||||
"isOn": cluster.GetIsOn(),
|
||||
"isDefault": cluster.GetIsDefault(),
|
||||
"countAllNodes": countAllNodes,
|
||||
"countActiveNodes": countActiveNodes,
|
||||
})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func findClusterMap(parent *actionutils.ParentAction, clusterID int64) (maps.Map, error) {
|
||||
if clusterID > 0 {
|
||||
resp, err := parent.RPC().HTTPDNSClusterRPC().FindHTTPDNSCluster(parent.AdminContext(), &pb.FindHTTPDNSClusterRequest{
|
||||
ClusterId: clusterID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.GetCluster() != nil {
|
||||
cluster := resp.GetCluster()
|
||||
return maps.Map{
|
||||
"id": cluster.GetId(),
|
||||
"name": cluster.GetName(),
|
||||
"gatewayDomain": cluster.GetServiceDomain(),
|
||||
"defaultTTL": cluster.GetDefaultTTL(),
|
||||
"fallbackTimeout": cluster.GetFallbackTimeoutMs(),
|
||||
"installDir": cluster.GetInstallDir(),
|
||||
"isOn": cluster.GetIsOn(),
|
||||
"isDefault": cluster.GetIsDefault(),
|
||||
"tlsPolicyJSON": cluster.GetTlsPolicyJSON(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
clusters, err := listClusterMaps(parent, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(clusters) == 0 {
|
||||
return maps.Map{
|
||||
"id": int64(0),
|
||||
"name": "",
|
||||
"gatewayDomain": "",
|
||||
"defaultTTL": 30,
|
||||
"fallbackTimeout": 300,
|
||||
"installDir": "/opt/edge-httpdns",
|
||||
}, nil
|
||||
}
|
||||
return clusters[0], nil
|
||||
}
|
||||
|
||||
func listNodeMaps(parent *actionutils.ParentAction, clusterID int64) ([]maps.Map, error) {
|
||||
resp, err := parent.RPC().HTTPDNSNodeRPC().ListHTTPDNSNodes(parent.AdminContext(), &pb.ListHTTPDNSNodesRequest{
|
||||
ClusterId: clusterID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]maps.Map, 0, len(resp.GetNodes()))
|
||||
for _, node := range resp.GetNodes() {
|
||||
statusMap := decodeNodeStatus(node.GetStatusJSON())
|
||||
installStatusMap := decodeInstallStatus(node.GetInstallStatusJSON())
|
||||
ip := node.GetName()
|
||||
if parsed := strings.TrimSpace(statusMap.GetString("hostIP")); len(parsed) > 0 {
|
||||
ip = parsed
|
||||
}
|
||||
nodeMap := maps.Map{
|
||||
"id": node.GetId(),
|
||||
"clusterId": node.GetClusterId(),
|
||||
"name": node.GetName(),
|
||||
"isOn": node.GetIsOn(),
|
||||
"isUp": node.GetIsUp(),
|
||||
"isInstalled": node.GetIsInstalled(),
|
||||
"isActive": node.GetIsActive(),
|
||||
"installDir": node.GetInstallDir(),
|
||||
"uniqueId": node.GetUniqueId(),
|
||||
"secret": node.GetSecret(),
|
||||
"status": statusMap,
|
||||
"installStatus": installStatusMap,
|
||||
"region": nil,
|
||||
"login": nil,
|
||||
"apiNodeAddrs": []string{},
|
||||
"cluster": maps.Map{
|
||||
"id": node.GetClusterId(),
|
||||
"installDir": node.GetInstallDir(),
|
||||
},
|
||||
"ipAddresses": []maps.Map{
|
||||
{
|
||||
"id": node.GetId(),
|
||||
"name": "Public IP",
|
||||
"ip": ip,
|
||||
"canAccess": true,
|
||||
"isOn": node.GetIsOn(),
|
||||
"isUp": node.GetIsUp(),
|
||||
},
|
||||
},
|
||||
}
|
||||
result = append(result, nodeMap)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func findNodeMap(parent *actionutils.ParentAction, nodeID int64) (maps.Map, error) {
|
||||
resp, err := parent.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(parent.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: nodeID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.GetNode() == nil {
|
||||
return maps.Map{}, nil
|
||||
}
|
||||
nodes, err := listNodeMaps(parent, resp.GetNode().GetClusterId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, node := range nodes {
|
||||
if node.GetInt64("id") == nodeID {
|
||||
return node, nil
|
||||
}
|
||||
}
|
||||
return maps.Map{
|
||||
"id": resp.GetNode().GetId(),
|
||||
"name": resp.GetNode().GetName(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createNode(parent *actionutils.ParentAction, clusterID int64, name string, installDir string) error {
|
||||
_, err := parent.RPC().HTTPDNSNodeRPC().CreateHTTPDNSNode(parent.AdminContext(), &pb.CreateHTTPDNSNodeRequest{
|
||||
ClusterId: clusterID,
|
||||
Name: strings.TrimSpace(name),
|
||||
InstallDir: strings.TrimSpace(installDir),
|
||||
IsOn: true,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func updateNode(parent *actionutils.ParentAction, nodeID int64, name string, installDir string, isOn bool) error {
|
||||
_, err := parent.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNode(parent.AdminContext(), &pb.UpdateHTTPDNSNodeRequest{
|
||||
NodeId: nodeID,
|
||||
Name: strings.TrimSpace(name),
|
||||
InstallDir: strings.TrimSpace(installDir),
|
||||
IsOn: isOn,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func deleteNode(parent *actionutils.ParentAction, nodeID int64) error {
|
||||
_, err := parent.RPC().HTTPDNSNodeRPC().DeleteHTTPDNSNode(parent.AdminContext(), &pb.DeleteHTTPDNSNodeRequest{
|
||||
NodeId: nodeID,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func decodeNodeStatus(raw []byte) maps.Map {
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
if len(raw) > 0 {
|
||||
_ = json.Unmarshal(raw, status)
|
||||
}
|
||||
cpuText := fmt.Sprintf("%.2f%%", status.CPUUsage*100)
|
||||
memText := fmt.Sprintf("%.2f%%", status.MemoryUsage*100)
|
||||
return maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"hostIP": status.HostIP,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": cpuText,
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": memText,
|
||||
"load1m": status.Load1m,
|
||||
"load5m": status.Load5m,
|
||||
"load15m": status.Load15m,
|
||||
"buildVersion": status.BuildVersion,
|
||||
"cpuPhysicalCount": status.CPUPhysicalCount,
|
||||
"cpuLogicalCount": status.CPULogicalCount,
|
||||
"exePath": status.ExePath,
|
||||
}
|
||||
}
|
||||
|
||||
func decodeInstallStatus(raw []byte) maps.Map {
|
||||
if len(raw) == 0 {
|
||||
return maps.Map{
|
||||
"isRunning": false,
|
||||
"isFinished": true,
|
||||
"isOk": true,
|
||||
"error": "",
|
||||
"errorCode": "",
|
||||
}
|
||||
}
|
||||
result := maps.Map{}
|
||||
if err := json.Unmarshal(raw, &result); err != nil {
|
||||
return maps.Map{
|
||||
"isRunning": false,
|
||||
"isFinished": true,
|
||||
"isOk": true,
|
||||
"error": "",
|
||||
"errorCode": "",
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,7 +1,14 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
@@ -12,18 +19,52 @@ type UpdateNodeSSHAction struct {
|
||||
func (this *UpdateNodeSSHAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
clusterId := int64(0)
|
||||
nodeName := ""
|
||||
if resp.GetNode() != nil {
|
||||
clusterId = resp.GetNode().GetClusterId()
|
||||
nodeName = resp.GetNode().GetName()
|
||||
}
|
||||
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["clusterId"] = 0
|
||||
this.Data["clusterId"] = clusterId
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": params.NodeId,
|
||||
"name": "Mock Node",
|
||||
"name": nodeName,
|
||||
}
|
||||
this.Data["loginId"] = 0
|
||||
this.Data["params"] = maps.Map{
|
||||
"host": "1.2.3.4",
|
||||
loginParams := maps.Map{
|
||||
"host": "",
|
||||
"port": 22,
|
||||
"grantId": 0,
|
||||
}
|
||||
this.Data["loginId"] = 0
|
||||
|
||||
if resp.GetNode() != nil && len(resp.GetNode().GetInstallStatusJSON()) > 0 {
|
||||
installStatus := maps.Map{}
|
||||
_ = json.Unmarshal(resp.GetNode().GetInstallStatusJSON(), &installStatus)
|
||||
sshInfo := installStatus.GetMap("ssh")
|
||||
if sshInfo != nil {
|
||||
if host := strings.TrimSpace(sshInfo.GetString("host")); len(host) > 0 {
|
||||
loginParams["host"] = host
|
||||
}
|
||||
if port := sshInfo.GetInt("port"); port > 0 {
|
||||
loginParams["port"] = port
|
||||
}
|
||||
if grantID := sshInfo.GetInt64("grantId"); grantID > 0 {
|
||||
loginParams["grantId"] = grantID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["params"] = loginParams
|
||||
this.Data["grant"] = nil
|
||||
this.Show()
|
||||
}
|
||||
@@ -34,6 +75,66 @@ func (this *UpdateNodeSSHAction) RunPost(params struct {
|
||||
SshHost string
|
||||
SshPort int
|
||||
GrantId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.SshHost = strings.TrimSpace(params.SshHost)
|
||||
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("请选择节点登录认证信息")
|
||||
}
|
||||
|
||||
if regexp.MustCompile(`^\d+\.\d+\.\d+\.\d+$`).MatchString(params.SshHost) && net.ParseIP(params.SshHost) == nil {
|
||||
this.Fail("SSH 主机地址 IP 格式错误")
|
||||
}
|
||||
|
||||
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := resp.GetNode()
|
||||
if node == nil {
|
||||
this.Fail("节点不存在")
|
||||
return
|
||||
}
|
||||
|
||||
installStatus := maps.Map{
|
||||
"isRunning": false,
|
||||
"isFinished": true,
|
||||
"isOk": node.GetIsInstalled(),
|
||||
"error": "",
|
||||
"errorCode": "",
|
||||
}
|
||||
if len(node.GetInstallStatusJSON()) > 0 {
|
||||
_ = json.Unmarshal(node.GetInstallStatusJSON(), &installStatus)
|
||||
}
|
||||
installStatus["ssh"] = maps.Map{
|
||||
"host": params.SshHost,
|
||||
"port": params.SshPort,
|
||||
"grantId": params.GrantId,
|
||||
}
|
||||
|
||||
installStatusJSON, _ := json.Marshal(installStatus)
|
||||
_, err = this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNodeStatus(this.AdminContext(), &pb.UpdateHTTPDNSNodeStatusRequest{
|
||||
NodeId: params.NodeId,
|
||||
IsUp: node.GetIsUp(),
|
||||
IsInstalled: node.GetIsInstalled(),
|
||||
IsActive: node.GetIsActive(),
|
||||
StatusJSON: node.GetStatusJSON(),
|
||||
InstallStatusJSON: installStatusJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user