Initial commit (code only without large binaries)
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package boards
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DomainStatsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DomainStatsAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
var hourFrom = timeutil.Format("YmdH", time.Now().Add(-23*time.Hour))
|
||||
var hourTo = timeutil.Format("YmdH")
|
||||
|
||||
resp, err := this.RPC().ServerDomainHourlyStatRPC().ListTopServerDomainStatsWithServerId(this.AdminContext(), &pb.ListTopServerDomainStatsWithServerIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
HourFrom: hourFrom,
|
||||
HourTo: hourTo,
|
||||
Size: 10,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 域名排行
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.DomainStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"serverId": stat.ServerId,
|
||||
"domain": stat.Domain,
|
||||
"countRequests": stat.CountRequests,
|
||||
"bytes": stat.Bytes,
|
||||
"countAttackRequests": stat.CountAttackRequests,
|
||||
"attackBytes": stat.AttackBytes,
|
||||
})
|
||||
}
|
||||
this.Data["topDomainStats"] = statMaps
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package boards
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
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/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "board", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
if !teaconst.IsPlus {
|
||||
this.Fail("only for commercial users")
|
||||
}
|
||||
|
||||
resp, err := this.RPC().ServerStatBoardRPC().ComposeServerStatNodeClusterBoard(this.AdminContext(), &pb.ComposeServerStatNodeClusterBoardRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["board"] = maps.Map{
|
||||
"countUsers": resp.CountUsers,
|
||||
"countActiveNodes": resp.CountActiveNodes,
|
||||
"countInactiveNodes": resp.CountInactiveNodes,
|
||||
"countServers": resp.CountServers,
|
||||
}
|
||||
|
||||
// 24小时流量趋势
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.HourlyTrafficStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"bytes": stat.Bytes,
|
||||
"cachedBytes": stat.CachedBytes,
|
||||
"countRequests": stat.CountRequests,
|
||||
"countCachedRequests": stat.CountCachedRequests,
|
||||
"countAttackRequests": stat.CountAttackRequests,
|
||||
"attackBytes": stat.AttackBytes,
|
||||
"day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
|
||||
"hour": stat.Hour[8:],
|
||||
})
|
||||
}
|
||||
this.Data["hourlyStats"] = statMaps
|
||||
}
|
||||
|
||||
// 15天流量趋势
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.DailyTrafficStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"bytes": stat.Bytes,
|
||||
"cachedBytes": stat.CachedBytes,
|
||||
"countRequests": stat.CountRequests,
|
||||
"countCachedRequests": stat.CountCachedRequests,
|
||||
"countAttackRequests": stat.CountAttackRequests,
|
||||
"attackBytes": stat.AttackBytes,
|
||||
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
||||
})
|
||||
}
|
||||
this.Data["dailyStats"] = statMaps
|
||||
}
|
||||
|
||||
// 当月流量
|
||||
this.Data["monthlyTraffic"] = numberutils.FormatBytes(resp.MonthlyTrafficBytes)
|
||||
|
||||
// 今日流量
|
||||
this.Data["todayTraffic"] = numberutils.FormatBytes(resp.DailyTrafficBytes)
|
||||
|
||||
// 昨日流量
|
||||
this.Data["yesterdayTraffic"] = numberutils.FormatBytes(resp.LastDailyTrafficBytes)
|
||||
|
||||
// 节点排行
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.TopNodeStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"nodeId": stat.NodeId,
|
||||
"nodeName": stat.NodeName,
|
||||
"countRequests": stat.CountRequests,
|
||||
"bytes": stat.Bytes,
|
||||
})
|
||||
}
|
||||
this.Data["topNodeStats"] = statMaps
|
||||
}
|
||||
|
||||
// CPU
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.CpuNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("usage"),
|
||||
})
|
||||
}
|
||||
this.Data["cpuValues"] = statMaps
|
||||
}
|
||||
|
||||
// Memory
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.MemoryNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("usage"),
|
||||
})
|
||||
}
|
||||
this.Data["memoryValues"] = statMaps
|
||||
}
|
||||
|
||||
// Load
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.LoadNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("load1m"),
|
||||
})
|
||||
}
|
||||
this.Data["loadValues"] = statMaps
|
||||
}
|
||||
|
||||
// 指标
|
||||
{
|
||||
var chartMaps = []maps.Map{}
|
||||
for _, chart := range resp.MetricDataCharts {
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range chart.MetricStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"keys": stat.Keys,
|
||||
"time": stat.Time,
|
||||
"value": stat.Value,
|
||||
"count": stat.SumCount,
|
||||
"total": stat.SumTotal,
|
||||
})
|
||||
}
|
||||
chartMaps = append(chartMaps, maps.Map{
|
||||
"chart": maps.Map{
|
||||
"id": chart.MetricChart.Id,
|
||||
"name": chart.MetricChart.Name,
|
||||
"widthDiv": chart.MetricChart.WidthDiv,
|
||||
"isOn": chart.MetricChart.IsOn,
|
||||
"maxItems": chart.MetricChart.MaxItems,
|
||||
"type": chart.MetricChart.Type,
|
||||
},
|
||||
"item": maps.Map{
|
||||
"id": chart.MetricChart.MetricItem.Id,
|
||||
"name": chart.MetricChart.MetricItem.Name,
|
||||
"period": chart.MetricChart.MetricItem.Period,
|
||||
"periodUnit": chart.MetricChart.MetricItem.PeriodUnit,
|
||||
"valueType": serverconfigs.FindMetricValueType(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||
"valueTypeName": serverconfigs.FindMetricValueName(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||
"keys": chart.MetricChart.MetricItem.Keys,
|
||||
},
|
||||
"stats": statMaps,
|
||||
})
|
||||
}
|
||||
this.Data["metricCharts"] = chartMaps
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateBatchAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateBatchAction) Init() {
|
||||
this.Nav("", "node", "create")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *CreateBatchAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
leftMenuItems := []maps.Map{
|
||||
{
|
||||
"name": this.Lang(codes.NodeMenu_CreateSingleNode),
|
||||
"url": "/clusters/cluster/createNode?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
|
||||
"isActive": false,
|
||||
},
|
||||
{
|
||||
"name": this.Lang(codes.NodeMenu_CreateMultipleNodes),
|
||||
"url": "/clusters/cluster/createBatch?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
|
||||
"isActive": true,
|
||||
},
|
||||
}
|
||||
this.Data["leftMenuItems"] = leftMenuItems
|
||||
|
||||
// 限额
|
||||
maxNodes, leftNodes, err := this.findNodesQuota()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["quota"] = maps.Map{
|
||||
"maxNodes": maxNodes,
|
||||
"leftNodes": leftNodes,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateBatchAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
GroupId int64
|
||||
RegionId int64
|
||||
IpList string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
if params.ClusterId <= 0 {
|
||||
this.Fail("请选择正确的集群")
|
||||
}
|
||||
|
||||
// 校验
|
||||
// TODO 支持IP范围,比如:192.168.1.[100-105]
|
||||
realIPList := []string{}
|
||||
for _, ip := range strings.Split(params.IpList, "\n") {
|
||||
ip = strings.TrimSpace(ip)
|
||||
if len(ip) == 0 {
|
||||
continue
|
||||
}
|
||||
ip = strings.ReplaceAll(ip, " ", "")
|
||||
|
||||
if net.ParseIP(ip) == nil {
|
||||
this.Fail("发现错误的IP地址:" + ip)
|
||||
}
|
||||
|
||||
if lists.ContainsString(realIPList, ip) {
|
||||
continue
|
||||
}
|
||||
realIPList = append(realIPList, ip)
|
||||
}
|
||||
|
||||
// 保存
|
||||
for _, ip := range realIPList {
|
||||
resp, err := this.RPC().NodeRPC().CreateNode(this.AdminContext(), &pb.CreateNodeRequest{
|
||||
Name: ip,
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
NodeLogin: nil,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
nodeId := resp.NodeId
|
||||
_, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
|
||||
NodeId: nodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
Name: "IP地址",
|
||||
Ip: ip,
|
||||
CanAccess: true,
|
||||
IsUp: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogCreateNodeBatch)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
|
||||
package cluster
|
||||
|
||||
func (this *CreateBatchAction) findNodesQuota() (maxNodes int32, leftNodes int32, err error) {
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package cluster
|
||||
|
||||
import "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
|
||||
func (this *CreateBatchAction) findNodesQuota() (maxNodes int32, leftNodes int32, err error) {
|
||||
quotaResp, err := this.RPC().AuthorityKeyRPC().FindAuthorityQuota(this.AdminContext(), &pb.FindAuthorityQuotaRequest{})
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
leftNodes = quotaResp.MaxNodes - quotaResp.CountNodes
|
||||
if leftNodes < 0 {
|
||||
leftNodes = 0
|
||||
}
|
||||
|
||||
return quotaResp.MaxNodes, leftNodes, nil
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CreateNodeAction 创建节点
|
||||
type CreateNodeAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) Init() {
|
||||
this.Nav("", "node", "create")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
if params.ClusterId <= 0 {
|
||||
this.RedirectURL("/clusters")
|
||||
return
|
||||
}
|
||||
|
||||
var leftMenuItems = []maps.Map{
|
||||
{
|
||||
"name": this.Lang(codes.NodeMenu_CreateSingleNode),
|
||||
"url": "/clusters/cluster/createNode?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
|
||||
"isActive": true,
|
||||
},
|
||||
{
|
||||
"name": this.Lang(codes.NodeMenu_CreateMultipleNodes),
|
||||
"url": "/clusters/cluster/createBatch?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
|
||||
"isActive": false,
|
||||
},
|
||||
}
|
||||
this.Data["leftMenuItems"] = leftMenuItems
|
||||
|
||||
// DNS线路
|
||||
clusterDNSResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var dnsRouteMaps = []maps.Map{}
|
||||
this.Data["dnsDomainId"] = 0
|
||||
if clusterDNSResp.Domain != nil {
|
||||
domainId := clusterDNSResp.Domain.Id
|
||||
this.Data["dnsDomainId"] = domainId
|
||||
if domainId > 0 {
|
||||
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: domainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, route := range routesResp.Routes {
|
||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
||||
"domainId": domainId,
|
||||
"domainName": clusterDNSResp.Domain.Name,
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["dnsRoutes"] = dnsRouteMaps
|
||||
|
||||
// API节点列表
|
||||
apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var apiNodes = apiNodesResp.ApiNodes
|
||||
var apiEndpoints = []string{}
|
||||
for _, apiNode := range apiNodes {
|
||||
if !apiNode.IsOn {
|
||||
continue
|
||||
}
|
||||
apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...)
|
||||
}
|
||||
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
||||
|
||||
// 安装文件下载
|
||||
this.Data["installerFiles"] = clusterutils.ListInstallerFiles()
|
||||
|
||||
// 限额
|
||||
maxNodes, leftNodes, err := this.findNodesQuota()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["quota"] = maps.Map{
|
||||
"maxNodes": maxNodes,
|
||||
"leftNodes": leftNodes,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) RunPost(params struct {
|
||||
Name string
|
||||
IpAddressesJSON []byte
|
||||
ClusterId int64
|
||||
GroupId int64
|
||||
RegionId int64
|
||||
GrantId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
|
||||
DnsDomainId int64
|
||||
DnsRoutesJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入节点名称")
|
||||
|
||||
if len(params.IpAddressesJSON) == 0 {
|
||||
this.Fail("请至少添加一个IP地址")
|
||||
}
|
||||
|
||||
// TODO 检查cluster
|
||||
if params.ClusterId <= 0 {
|
||||
this.Fail("请选择所在集群")
|
||||
}
|
||||
|
||||
// IP地址
|
||||
var ipAddresses = []maps.Map{}
|
||||
if len(params.IpAddressesJSON) > 0 {
|
||||
err := json.Unmarshal(params.IpAddressesJSON, &ipAddresses)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(ipAddresses) == 0 {
|
||||
// 检查Name中是否包含IP
|
||||
var ipv4Reg = regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`)
|
||||
var ipMatches = ipv4Reg.FindStringSubmatch(params.Name)
|
||||
if len(ipMatches) > 0 {
|
||||
var nodeIP = ipMatches[0]
|
||||
if net.ParseIP(nodeIP) != nil {
|
||||
ipAddresses = []maps.Map{
|
||||
{
|
||||
"ip": nodeIP,
|
||||
"canAccess": true,
|
||||
"isOn": true,
|
||||
"isUp": true,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(ipAddresses) == 0 {
|
||||
this.Fail("请至少输入一个IP地址")
|
||||
}
|
||||
}
|
||||
|
||||
var dnsRouteCodes = []string{}
|
||||
if len(params.DnsRoutesJSON) > 0 {
|
||||
err := json.Unmarshal(params.DnsRoutesJSON, &dnsRouteCodes)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 检查登录授权
|
||||
var loginInfo = &pb.NodeLogin{
|
||||
Id: 0,
|
||||
Name: "SSH",
|
||||
Type: "ssh",
|
||||
Params: maps.Map{
|
||||
"grantId": params.GrantId,
|
||||
"host": params.SshHost,
|
||||
"port": params.SshPort,
|
||||
}.AsJSON(),
|
||||
}
|
||||
|
||||
// 保存
|
||||
createResp, err := this.RPC().NodeRPC().CreateNode(this.AdminContext(), &pb.CreateNodeRequest{
|
||||
Name: params.Name,
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
NodeLogin: loginInfo,
|
||||
DnsDomainId: params.DnsDomainId,
|
||||
DnsRoutes: dnsRouteCodes,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var nodeId = createResp.NodeId
|
||||
|
||||
// IP地址
|
||||
var resultIPAddresses = []string{}
|
||||
for _, addr := range ipAddresses {
|
||||
var resultAddrIds = []int64{}
|
||||
|
||||
addrId := addr.GetInt64("id")
|
||||
if addrId > 0 {
|
||||
resultAddrIds = append(resultAddrIds, addrId)
|
||||
_, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{
|
||||
NodeIPAddressId: addrId,
|
||||
NodeId: nodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
resultIPAddresses = append(resultIPAddresses, addr.GetString("ip"))
|
||||
} else {
|
||||
var ipStrings = addr.GetString("ip")
|
||||
result, err := utils.ExtractIP(ipStrings)
|
||||
if err != nil {
|
||||
this.Fail("节点创建成功,但是保存IP失败:" + err.Error())
|
||||
}
|
||||
|
||||
resultIPAddresses = append(resultIPAddresses, result...)
|
||||
|
||||
if len(result) == 1 {
|
||||
// 单个创建
|
||||
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
|
||||
NodeId: nodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
Name: addr.GetString("name"),
|
||||
Ip: result[0],
|
||||
CanAccess: addr.GetBool("canAccess"),
|
||||
IsUp: addr.GetBool("isUp"),
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
addrId = createResp.NodeIPAddressId
|
||||
resultAddrIds = append(resultAddrIds, addrId)
|
||||
} else if len(result) > 1 {
|
||||
// 批量创建
|
||||
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddresses(this.AdminContext(), &pb.CreateNodeIPAddressesRequest{
|
||||
NodeId: nodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
Name: addr.GetString("name"),
|
||||
IpList: result,
|
||||
CanAccess: addr.GetBool("canAccess"),
|
||||
IsUp: addr.GetBool("isUp"),
|
||||
GroupValue: ipStrings,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
resultAddrIds = append(resultAddrIds, createResp.NodeIPAddressIds...)
|
||||
}
|
||||
}
|
||||
|
||||
// 阈值
|
||||
var thresholds = addr.GetSlice("thresholds")
|
||||
if len(thresholds) > 0 {
|
||||
thresholdsJSON, err := json.Marshal(thresholds)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, addrId := range resultAddrIds {
|
||||
_, err = this.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(this.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
|
||||
NodeIPAddressId: addrId,
|
||||
NodeIPAddressThresholdsJSON: thresholdsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogCreateNode, nodeId)
|
||||
|
||||
// 响应数据
|
||||
this.Data["nodeId"] = nodeId
|
||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: nodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if nodeResp.Node != nil {
|
||||
var grantMap maps.Map = nil
|
||||
grantId := params.GrantId
|
||||
if grantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.NodeGrant != nil && grantResp.NodeGrant.Id > 0 {
|
||||
grantMap = maps.Map{
|
||||
"id": grantResp.NodeGrant.Id,
|
||||
"name": grantResp.NodeGrant.Name,
|
||||
"method": grantResp.NodeGrant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method, this.LangCode()),
|
||||
"username": grantResp.NodeGrant.Username,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": nodeResp.Node.Id,
|
||||
"name": nodeResp.Node.Name,
|
||||
"uniqueId": nodeResp.Node.UniqueId,
|
||||
"secret": nodeResp.Node.Secret,
|
||||
"addresses": resultIPAddresses,
|
||||
"login": maps.Map{
|
||||
"id": 0,
|
||||
"name": "SSH",
|
||||
"type": "ssh",
|
||||
"params": maps.Map{
|
||||
"grantId": params.GrantId,
|
||||
"host": params.SshHost,
|
||||
"port": params.SshPort,
|
||||
},
|
||||
},
|
||||
"grant": grantMap,
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type CreateNodeInstallAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateNodeInstallAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
GrantId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeSSH_LogUpdateNodeSSH, params.NodeId)
|
||||
|
||||
params.Must.
|
||||
Field("sshHost2", params.SshHost).
|
||||
Require("请填写SSH主机地址").
|
||||
Field("sshPort2", params.SshPort).
|
||||
Gt(0, "请填写SSH主机端口").
|
||||
Lt(65535, "SSH主机端口需要小于65535").
|
||||
Field("grantId", params.GrantId).
|
||||
Gt(0, "请选择SSH登录认证")
|
||||
|
||||
// 查询login
|
||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var node = nodeResp.Node
|
||||
if node == nil {
|
||||
this.Fail("找不到要修改的节点")
|
||||
}
|
||||
var loginId int64
|
||||
if node.NodeLogin != nil {
|
||||
loginId = node.NodeLogin.Id
|
||||
}
|
||||
|
||||
// 修改节点信息
|
||||
_, err = this.RPC().NodeRPC().UpdateNodeLogin(this.AdminContext(), &pb.UpdateNodeLoginRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeLogin: &pb.NodeLogin{
|
||||
Id: loginId,
|
||||
Name: "SSH",
|
||||
Type: "ssh",
|
||||
Params: maps.Map{
|
||||
"grantId": params.GrantId,
|
||||
"host": params.SshHost,
|
||||
"port": params.SshPort,
|
||||
}.AsJSON(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 开始安装
|
||||
_, err = this.RPC().NodeRPC().InstallNode(this.AdminContext(), &pb.InstallNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.Fail("安装失败:" + err.Error())
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
|
||||
package cluster
|
||||
|
||||
func (this *CreateNodeAction) findNodesQuota() (maxNodes int32, leftNodes int32, err error) {
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package cluster
|
||||
|
||||
import "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
|
||||
func (this *CreateNodeAction) findNodesQuota() (maxNodes int32, leftNodes int32, err error) {
|
||||
quotaResp, err := this.RPC().AuthorityKeyRPC().FindAuthorityQuota(this.AdminContext(), &pb.FindAuthorityQuotaRequest{})
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
leftNodes = quotaResp.MaxNodes - quotaResp.CountNodes
|
||||
if leftNodes < 0 {
|
||||
leftNodes = 0
|
||||
}
|
||||
|
||||
return quotaResp.MaxNodes, leftNodes, nil
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) Init() {
|
||||
this.Nav("", "delete", "index")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
// 检查有无服务正在使用
|
||||
countResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithNodeClusterId(this.AdminContext(), &pb.CountAllEnabledServersWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("有代理服务正在使用此集群,请修改这些代理服务后再删除")
|
||||
}
|
||||
|
||||
// 删除
|
||||
_, err = this.RPC().NodeClusterRPC().DeleteNodeCluster(this.AdminContext(), &pb.DeleteNodeClusterRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeCluster_LogDeleteCluster, params.ClusterId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type DownloadInstallerAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DownloadInstallerAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *DownloadInstallerAction) RunGet(params struct {
|
||||
Name string
|
||||
}) {
|
||||
if len(params.Name) == 0 {
|
||||
this.ResponseWriter.WriteHeader(http.StatusNotFound)
|
||||
this.WriteString("file not found")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查文件名
|
||||
// 以防止路径穿越等风险
|
||||
if !regexp.MustCompile(`^[a-zA-Z0-9.-]+$`).MatchString(params.Name) {
|
||||
this.ResponseWriter.WriteHeader(http.StatusNotFound)
|
||||
this.WriteString("file not found")
|
||||
return
|
||||
}
|
||||
|
||||
var zipFile = Tea.Root + "/edge-api/deploy/" + params.Name
|
||||
fp, err := os.OpenFile(zipFile, os.O_RDWR, 0444)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
this.ResponseWriter.WriteHeader(http.StatusNotFound)
|
||||
this.WriteString("file not found")
|
||||
return
|
||||
}
|
||||
|
||||
this.ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
||||
this.WriteString("file can not be opened")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = fp.Close()
|
||||
}()
|
||||
|
||||
stat, err := fp.Stat()
|
||||
if err != nil {
|
||||
this.ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
||||
this.WriteString("file can not be opened")
|
||||
return
|
||||
}
|
||||
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\""+params.Name+"\";")
|
||||
this.AddHeader("Content-Type", "application/zip")
|
||||
this.AddHeader("Content-Length", types.String(stat.Size()))
|
||||
_, _ = io.Copy(this.ResponseWriter, fp)
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Name string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
if params.ClusterId <= 0 {
|
||||
this.Fail("请选择集群")
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
createResp, err := this.RPC().NodeGroupRPC().CreateNodeGroup(this.AdminContext(), &pb.CreateNodeGroupRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": createResp.NodeGroupId,
|
||||
"name": params.Name,
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeGroup_LogCreateNodeGroup, createResp.NodeGroupId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
}) {
|
||||
// 检查是否正在使用
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{NodeGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("此分组正在被使用不能删除,请修改节点后再删除")
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeGroupRPC().DeleteNodeGroup(this.AdminContext(), &pb.DeleteNodeGroupRequest{NodeGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeGroup_LogDeleteNodeGroup, params.GroupId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "group")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.NodeGroups {
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{NodeGroupId: group.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countNodes := countResp.Count
|
||||
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"countNodes": countNodes,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.NodeGroups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
if params.GroupId <= 0 {
|
||||
this.Fail("请选择要使用的分组")
|
||||
}
|
||||
|
||||
groupResp, err := this.RPC().NodeGroupRPC().FindEnabledNodeGroup(this.AdminContext(), &pb.FindEnabledNodeGroupRequest{NodeGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
group := groupResp.NodeGroup
|
||||
if group == nil {
|
||||
this.NotFound("nodeGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type SortAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SortAction) RunPost(params struct {
|
||||
GroupIds []int64
|
||||
}) {
|
||||
_, err := this.RPC().NodeGroupRPC().UpdateNodeGroupOrders(this.AdminContext(), &pb.UpdateNodeGroupOrdersRequest{NodeGroupIds: params.GroupIds})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeGroup_LogSortNodeGroups)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
GroupId int64
|
||||
}) {
|
||||
groupResp, err := this.RPC().NodeGroupRPC().FindEnabledNodeGroup(this.AdminContext(), &pb.FindEnabledNodeGroupRequest{NodeGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
group := groupResp.NodeGroup
|
||||
if group == nil {
|
||||
this.NotFound("nodeGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
Name string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
_, err := this.RPC().NodeGroupRPC().UpdateNodeGroup(this.AdminContext(), &pb.UpdateNodeGroupRequest{
|
||||
NodeGroupId: params.GroupId,
|
||||
Name: params.Name,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeGroup_LogUpdateNodeGroup, params.GroupId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
if teaconst.IsPlus {
|
||||
this.RedirectURL("/clusters/cluster/boards?clusterId=" + strconv.FormatInt(params.ClusterId, 10))
|
||||
} else {
|
||||
this.RedirectURL("/clusters/cluster/nodes?clusterId=" + strconv.FormatInt(params.ClusterId, 10))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/groups"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/cache"
|
||||
ddosProtection "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/ddos-protection"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/dns"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/ssh"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/system"
|
||||
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNode)).
|
||||
Helper(clusters.NewClusterHelper()).
|
||||
Data("teaMenu", "clusters").
|
||||
Data("teaSubMenu", "cluster").
|
||||
Prefix("/clusters/cluster").
|
||||
Get("", new(IndexAction)).
|
||||
Get("/nodes", new(NodesAction)).
|
||||
GetPost("/installNodes", new(InstallNodesAction)).
|
||||
GetPost("/installRemote", new(InstallRemoteAction)).
|
||||
Post("/installStatus", new(InstallStatusAction)).
|
||||
GetPost("/upgradeRemote", new(UpgradeRemoteAction)).
|
||||
Post("/upgradeStatus", new(UpgradeStatusAction)).
|
||||
GetPost("/delete", new(DeleteAction)).
|
||||
GetPost("/createNode", new(CreateNodeAction)).
|
||||
Post("/createNodeInstall", new(CreateNodeInstallAction)).
|
||||
GetPost("/createBatch", new(CreateBatchAction)).
|
||||
GetPost("/updateNodeSSH", new(UpdateNodeSSHAction)).
|
||||
GetPost("/installManual", new(InstallManualAction)).
|
||||
Post("/suggestLoginPorts", new(SuggestLoginPortsAction)).
|
||||
Get("/downloadInstaller", new(DownloadInstallerAction)).
|
||||
|
||||
// 节点相关
|
||||
Prefix("/clusters/cluster/node").
|
||||
Get("", new(node.IndexAction)).
|
||||
GetPost("/update", new(node.UpdateAction)).
|
||||
GetPost("/install", new(node.InstallAction)).
|
||||
Post("/updateInstallStatus", new(node.UpdateInstallStatusAction)).
|
||||
Post("/status", new(node.StatusAction)).
|
||||
Get("/logs", new(node.LogsAction)).
|
||||
Post("/start", new(node.StartAction)).
|
||||
Post("/stop", new(node.StopAction)).
|
||||
Post("/uninstall", new(node.UninstallAction)).
|
||||
Post("/up", new(node.UpAction)).
|
||||
Post("/updateIsOn", new(node.UpdateIsOnAction)).
|
||||
Get("/detail", new(node.DetailAction)).
|
||||
GetPost("/updateDNSPopup", new(node.UpdateDNSPopupAction)).
|
||||
Post("/syncDomain", new(node.SyncDomainAction)).
|
||||
GetPost("/settings/cache", new(cache.IndexAction)).
|
||||
GetPost("/settings/dns", new(dns.IndexAction)).
|
||||
GetPost("/settings/system", new(system.IndexAction)).
|
||||
GetPost("/settings/ssh", new(ssh.IndexAction)).
|
||||
GetPost("/settings/ssh/test", new(ssh.TestAction)).
|
||||
GetPost("/settings/ddos-protection", new(ddosProtection.IndexAction)).
|
||||
Post("/settings/ddos-protection/status", new(ddosProtection.StatusAction)).
|
||||
|
||||
// 分组相关
|
||||
Prefix("/clusters/cluster/groups").
|
||||
Get("", new(groups.IndexAction)).
|
||||
GetPost("/createPopup", new(groups.CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(groups.UpdatePopupAction)).
|
||||
Post("/delete", new(groups.DeleteAction)).
|
||||
Post("/sort", new(groups.SortAction)).
|
||||
GetPost("/selectPopup", new(groups.SelectPopupAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
//go:build plus
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/boards"
|
||||
nodeboards "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/boards"
|
||||
nodeschedule "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/schedule"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/schedule/actions"
|
||||
nodethresholds "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/thresholds"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/cc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/http3"
|
||||
networksecurity "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/network-security"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/pages"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/thresholds"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/uam"
|
||||
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNode)).
|
||||
Helper(clusters.NewClusterHelper()).
|
||||
Data("teaMenu", "clusters").
|
||||
Data("teaSubMenu", "cluster").
|
||||
|
||||
// 节点相关
|
||||
Prefix("/clusters/cluster/node").
|
||||
GetPost("/boards", new(nodeboards.IndexAction)).
|
||||
Post("/boards/data", new(nodeboards.DataAction)).
|
||||
Post("/boards/domainStats", new(nodeboards.DomainStatsAction)).
|
||||
|
||||
// 看板相关
|
||||
Prefix("/clusters/cluster/boards").
|
||||
GetPost("", new(boards.IndexAction)).
|
||||
Post("/domainStats", new(boards.DomainStatsAction)).
|
||||
|
||||
// 集群设置相关
|
||||
Prefix("/clusters/cluster/settings").
|
||||
GetPost("/uam", new(uam.IndexAction)).
|
||||
GetPost("/cc", new(cc.IndexAction)).
|
||||
GetPost("/pages", new(pages.IndexAction)).
|
||||
|
||||
//
|
||||
GetPost("/http3", new(http3.IndexAction)).
|
||||
GetPost("/http3/test", new(http3.TestAction)).
|
||||
|
||||
//
|
||||
GetPost("/thresholds", new(thresholds.IndexAction)).
|
||||
|
||||
//
|
||||
GetPost("/network-security", new(networksecurity.IndexAction)).
|
||||
|
||||
// 节点设置相关
|
||||
Prefix("/clusters/cluster/node/settings").
|
||||
Get("/thresholds", new(nodethresholds.IndexAction)).
|
||||
GetPost("/schedule", new(nodeschedule.IndexAction)).
|
||||
Post("/schedule/resetActionStatus", new(nodeschedule.ResetActionStatusAction)).
|
||||
GetPost("/schedule/actions/createPopup", new(scheduleactions.CreatePopupAction)).
|
||||
GetPost("/schedule/actions/updatePopup", new(scheduleactions.UpdatePopupAction)).
|
||||
Post("/schedule/actions/delete", new(scheduleactions.DeleteAction)).
|
||||
Post("/schedule/actions/copyToGroup", new(scheduleactions.CopyToGroupAction)).
|
||||
Post("/schedule/actions/copyToCluster", new(scheduleactions.CopyToClusterAction)).
|
||||
Post("/schedule/actions/updateOrders", new(scheduleactions.UpdateActionsAction)).
|
||||
|
||||
//
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type InstallManualAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *InstallManualAction) Init() {
|
||||
this.Nav("", "node", "install")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *InstallManualAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["leftMenuItems"] = LeftMenuItemsForInstall(this.AdminContext(), params.ClusterId, "manual", this.LangCode())
|
||||
|
||||
nodesResp, err := this.RPC().NodeRPC().FindAllNotInstalledNodesWithNodeClusterId(this.AdminContext(), &pb.FindAllNotInstalledNodesWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
nodeMaps := []maps.Map{}
|
||||
for _, node := range nodesResp.Nodes {
|
||||
loginParams := maps.Map{}
|
||||
if node.NodeLogin != nil && len(node.NodeLogin.Params) > 0 {
|
||||
err := json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
installStatus := maps.Map{
|
||||
"isRunning": false,
|
||||
"isFinished": false,
|
||||
}
|
||||
if node.InstallStatus != nil {
|
||||
installStatus = maps.Map{
|
||||
"isRunning": node.InstallStatus.IsRunning,
|
||||
"isFinished": node.InstallStatus.IsFinished,
|
||||
"isOk": node.InstallStatus.IsOk,
|
||||
"error": node.InstallStatus.Error,
|
||||
}
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"isOn": node.IsOn,
|
||||
"name": node.Name,
|
||||
"addresses": node.IpAddresses,
|
||||
"login": node.NodeLogin,
|
||||
"loginParams": loginParams,
|
||||
"installStatus": installStatus,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type InstallNodesAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *InstallNodesAction) Init() {
|
||||
this.Nav("", "node", "install")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *InstallNodesAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["leftMenuItems"] = LeftMenuItemsForInstall(this.AdminContext(), params.ClusterId, "register", this.LangCode())
|
||||
|
||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if clusterResp.NodeCluster == nil {
|
||||
this.NotFound("nodeCluster", params.ClusterId)
|
||||
return
|
||||
}
|
||||
|
||||
cluster := clusterResp.NodeCluster
|
||||
|
||||
clusterAPINodesResp, err := this.RPC().NodeClusterRPC().FindAPINodesWithNodeCluster(this.AdminContext(), &pb.FindAPINodesWithNodeClusterRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
apiNodeAddrs := []string{}
|
||||
if clusterAPINodesResp.UseAllAPINodes {
|
||||
apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, apiNode := range apiNodesResp.ApiNodes {
|
||||
if !apiNode.IsOn {
|
||||
continue
|
||||
}
|
||||
apiNodeAddrs = append(apiNodeAddrs, apiNode.AccessAddrs...)
|
||||
}
|
||||
} else {
|
||||
for _, apiNode := range clusterAPINodesResp.ApiNodes {
|
||||
if !apiNode.IsOn {
|
||||
continue
|
||||
}
|
||||
apiNodeAddrs = append(apiNodeAddrs, apiNode.AccessAddrs...)
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["cluster"] = maps.Map{
|
||||
"uniqueId": cluster.UniqueId,
|
||||
"secret": cluster.Secret,
|
||||
"endpoints": "\"" + strings.Join(apiNodeAddrs, "\", \"") + "\"",
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type InstallRemoteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *InstallRemoteAction) Init() {
|
||||
this.Nav("", "node", "install")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *InstallRemoteAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["leftMenuItems"] = LeftMenuItemsForInstall(this.AdminContext(), params.ClusterId, "install", this.LangCode())
|
||||
|
||||
nodesResp, err := this.RPC().NodeRPC().FindAllNotInstalledNodesWithNodeClusterId(this.AdminContext(), &pb.FindAllNotInstalledNodesWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
nodeMaps := []maps.Map{}
|
||||
for _, node := range nodesResp.Nodes {
|
||||
loginParams := maps.Map{}
|
||||
if node.NodeLogin != nil && len(node.NodeLogin.Params) > 0 {
|
||||
err := json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
installStatus := maps.Map{
|
||||
"isRunning": false,
|
||||
"isFinished": false,
|
||||
}
|
||||
if node.InstallStatus != nil {
|
||||
installStatus = maps.Map{
|
||||
"isRunning": node.InstallStatus.IsRunning,
|
||||
"isFinished": node.InstallStatus.IsFinished,
|
||||
"isOk": node.InstallStatus.IsOk,
|
||||
"error": node.InstallStatus.Error,
|
||||
}
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"isOn": node.IsOn,
|
||||
"name": node.Name,
|
||||
"addresses": node.IpAddresses,
|
||||
"login": node.NodeLogin,
|
||||
"loginParams": loginParams,
|
||||
"installStatus": installStatus,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *InstallRemoteAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
_, err := this.RPC().NodeRPC().InstallNode(this.AdminContext(), &pb.InstallNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogInstallNodeRemotely, params.NodeId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type InstallStatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *InstallStatusAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeRPC().FindNodeInstallStatus(this.AdminContext(), &pb.FindNodeInstallStatusRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.InstallStatus == nil {
|
||||
this.Data["status"] = nil
|
||||
this.Success()
|
||||
}
|
||||
|
||||
this.Data["status"] = maps.Map{
|
||||
"isRunning": resp.InstallStatus.IsRunning,
|
||||
"isFinished": resp.InstallStatus.IsFinished,
|
||||
"isOk": resp.InstallStatus.IsOk,
|
||||
"error": resp.InstallStatus.Error,
|
||||
"errorCode": resp.InstallStatus.ErrorCode,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package boards
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type DataAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DataAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().ServerStatBoardRPC().ComposeServerStatNodeBoard(this.AdminContext(), &pb.ComposeServerStatNodeBoardRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["board"] = maps.Map{
|
||||
"isActive": resp.IsActive,
|
||||
"trafficInBytes": resp.TrafficInBytes,
|
||||
"trafficOutBytes": resp.TrafficOutBytes,
|
||||
"countConnections": resp.CountConnections,
|
||||
"countRequests": resp.CountRequests,
|
||||
"countAttackRequests": resp.CountAttackRequests,
|
||||
"cpuUsage": resp.CpuUsage,
|
||||
"memoryUsage": resp.MemoryUsage,
|
||||
"memoryTotalSize": resp.MemoryTotalSize,
|
||||
"load": resp.Load,
|
||||
"cacheDiskSize": resp.CacheDiskSize,
|
||||
"cacheMemorySize": resp.CacheMemorySize,
|
||||
"monthlyTrafficBytes": resp.MonthlyTrafficBytes,
|
||||
"todayTrafficBytes": resp.DailyTrafficBytes,
|
||||
"yesterdayTrafficBytes": resp.LastDailyTrafficBytes,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package boards
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DomainStatsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DomainStatsAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
var hourFrom = timeutil.Format("YmdH", time.Now().Add(-23*time.Hour))
|
||||
var hourTo = timeutil.Format("YmdH")
|
||||
|
||||
resp, err := this.RPC().ServerDomainHourlyStatRPC().ListTopServerDomainStatsWithServerId(this.AdminContext(), &pb.ListTopServerDomainStatsWithServerIdRequest{
|
||||
NodeId: params.NodeId,
|
||||
HourFrom: hourFrom,
|
||||
HourTo: hourTo,
|
||||
Size: 10,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 域名排行
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.DomainStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"serverId": stat.ServerId,
|
||||
"domain": stat.Domain,
|
||||
"countRequests": stat.CountRequests,
|
||||
"bytes": stat.Bytes,
|
||||
"countAttackRequests": stat.CountAttackRequests,
|
||||
"attackBytes": stat.AttackBytes,
|
||||
})
|
||||
}
|
||||
this.Data["topDomainStats"] = statMaps
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package boards
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"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/shared"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "board")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
if !teaconst.IsPlus {
|
||||
this.RedirectURL("/clusters/cluster/node?clusterId=" + strconv.FormatInt(params.ClusterId, 10) + "&nodeId=" + strconv.FormatInt(params.NodeId, 10))
|
||||
return
|
||||
}
|
||||
|
||||
pbNode, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// disk information
|
||||
this.Data["diskWritingSpeedMB"] = 0
|
||||
this.Data["diskWritingSpeedMBDelta"] = 0
|
||||
if !utils.JSONIsNull(pbNode.StatusJSON) {
|
||||
var statusConfig = &nodeconfigs.NodeStatus{}
|
||||
err = json.Unmarshal(pbNode.StatusJSON, statusConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["diskWritingSpeedMB"] = statusConfig.DiskWritingSpeedMB
|
||||
}
|
||||
|
||||
// max cache capacity
|
||||
this.Data["cacheDiskCapacityBytes"] = 0
|
||||
if pbNode.MaxCacheDiskCapacity == nil {
|
||||
pbNode.MaxCacheDiskCapacity = &pb.SizeCapacity{Count: 0, Unit: "byte"}
|
||||
}
|
||||
var capacityBytes = (&shared.SizeCapacity{
|
||||
Count: pbNode.MaxCacheDiskCapacity.Count,
|
||||
Unit: pbNode.MaxCacheDiskCapacity.Unit,
|
||||
}).Bytes()
|
||||
if capacityBytes <= 0 && params.ClusterId > 0 {
|
||||
// lookup cache policy for cluster
|
||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if clusterResp.NodeCluster != nil && clusterResp.NodeCluster.HttpCachePolicyId > 0 {
|
||||
cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{HttpCachePolicyId: clusterResp.NodeCluster.HttpCachePolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var cachePolicyJSON = cachePolicyResp.HttpCachePolicyJSON
|
||||
if !utils.JSONIsNull(cachePolicyJSON) {
|
||||
var cachePolicy = &serverconfigs.HTTPCachePolicy{}
|
||||
err = json.Unmarshal(cachePolicyJSON, cachePolicy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if cachePolicy.IsOn && cachePolicy.Type == serverconfigs.CachePolicyStorageFile && cachePolicy.Capacity != nil {
|
||||
capacityBytes = cachePolicy.Capacity.Bytes()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if capacityBytes > 0 {
|
||||
this.Data["cacheDiskCapacityBytes"] = capacityBytes
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().ServerStatBoardRPC().ComposeServerStatNodeBoard(this.AdminContext(), &pb.ComposeServerStatNodeBoardRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["board"] = maps.Map{
|
||||
"isActive": resp.IsActive,
|
||||
"trafficInBytes": resp.TrafficInBytes,
|
||||
"trafficOutBytes": resp.TrafficOutBytes,
|
||||
"countConnections": resp.CountConnections,
|
||||
"countRequests": resp.CountRequests,
|
||||
"countAttackRequests": resp.CountAttackRequests,
|
||||
"cpuUsage": resp.CpuUsage,
|
||||
"memoryUsage": resp.MemoryUsage,
|
||||
"memoryTotalSize": resp.MemoryTotalSize,
|
||||
"load": resp.Load,
|
||||
"cacheDiskSize": resp.CacheDiskSize,
|
||||
"cacheMemorySize": resp.CacheMemorySize,
|
||||
"monthlyTrafficBytes": resp.MonthlyTrafficBytes,
|
||||
"todayTrafficBytes": resp.DailyTrafficBytes,
|
||||
"yesterdayTrafficBytes": resp.LastDailyTrafficBytes,
|
||||
}
|
||||
|
||||
// 24小时流量趋势
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.HourlyTrafficStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"bytes": stat.Bytes,
|
||||
"cachedBytes": stat.CachedBytes,
|
||||
"countRequests": stat.CountRequests,
|
||||
"countCachedRequests": stat.CountCachedRequests,
|
||||
"countAttackRequests": stat.CountAttackRequests,
|
||||
"attackBytes": stat.AttackBytes,
|
||||
"day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
|
||||
"hour": stat.Hour[8:],
|
||||
})
|
||||
}
|
||||
this.Data["hourlyStats"] = statMaps
|
||||
}
|
||||
|
||||
// 15天流量趋势
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.DailyTrafficStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"bytes": stat.Bytes,
|
||||
"cachedBytes": stat.CachedBytes,
|
||||
"countRequests": stat.CountRequests,
|
||||
"countCachedRequests": stat.CountCachedRequests,
|
||||
"countAttackRequests": stat.CountAttackRequests,
|
||||
"attackBytes": stat.AttackBytes,
|
||||
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
||||
})
|
||||
}
|
||||
this.Data["dailyStats"] = statMaps
|
||||
}
|
||||
|
||||
// CPU
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.CpuNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("usage"),
|
||||
})
|
||||
}
|
||||
this.Data["cpuValues"] = statMaps
|
||||
}
|
||||
|
||||
// Memory
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.MemoryNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("usage"),
|
||||
})
|
||||
}
|
||||
this.Data["memoryValues"] = statMaps
|
||||
}
|
||||
|
||||
// Load
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.LoadNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("load1m"),
|
||||
})
|
||||
}
|
||||
this.Data["loadValues"] = statMaps
|
||||
}
|
||||
|
||||
// CacheDirs
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.CacheDirsValues {
|
||||
var m = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &m)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": m,
|
||||
})
|
||||
}
|
||||
this.Data["cacheDirValues"] = statMaps
|
||||
}
|
||||
|
||||
// Network Packets
|
||||
{
|
||||
var hasData = false
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.NetworkPacketsValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var tcpInPPS = valueMap.GetUint64("tcpInPPS")
|
||||
var udpInPPS = valueMap.GetUint64("udpInPPS")
|
||||
var icmpInPPS = valueMap.GetUint64("icmpInPPS")
|
||||
|
||||
if tcpInPPS > 0 || udpInPPS > 0 || icmpInPPS > 0 {
|
||||
hasData = true
|
||||
}
|
||||
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"tcpInPPS": tcpInPPS,
|
||||
"udpInPPS": udpInPPS,
|
||||
"icmpInPPS": icmpInPPS,
|
||||
})
|
||||
}
|
||||
if !hasData {
|
||||
statMaps = []maps.Map{}
|
||||
}
|
||||
this.Data["networkPacketsValues"] = statMaps
|
||||
}
|
||||
|
||||
// 指标
|
||||
{
|
||||
var chartMaps = []maps.Map{}
|
||||
for _, chart := range resp.MetricDataCharts {
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range chart.MetricStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"keys": stat.Keys,
|
||||
"time": stat.Time,
|
||||
"value": stat.Value,
|
||||
"count": stat.SumCount,
|
||||
"total": stat.SumTotal,
|
||||
})
|
||||
}
|
||||
chartMaps = append(chartMaps, maps.Map{
|
||||
"chart": maps.Map{
|
||||
"id": chart.MetricChart.Id,
|
||||
"name": chart.MetricChart.Name,
|
||||
"widthDiv": chart.MetricChart.WidthDiv,
|
||||
"isOn": chart.MetricChart.IsOn,
|
||||
"maxItems": chart.MetricChart.MaxItems,
|
||||
"type": chart.MetricChart.Type,
|
||||
},
|
||||
"item": maps.Map{
|
||||
"id": chart.MetricChart.MetricItem.Id,
|
||||
"name": chart.MetricChart.MetricItem.Name,
|
||||
"period": chart.MetricChart.MetricItem.Period,
|
||||
"periodUnit": chart.MetricChart.MetricItem.PeriodUnit,
|
||||
"valueType": serverconfigs.FindMetricValueType(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||
"valueTypeName": serverconfigs.FindMetricValueName(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||
"keys": chart.MetricChart.MetricItem.Keys,
|
||||
},
|
||||
"stats": statMaps,
|
||||
})
|
||||
}
|
||||
this.Data["metricCharts"] = chartMaps
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,403 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iputils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DetailAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DetailAction) Init() {
|
||||
this.Nav("", "node", "node")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *DetailAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var node = nodeResp.Node
|
||||
if node == nil {
|
||||
this.WriteString("找不到要操作的节点")
|
||||
return
|
||||
}
|
||||
|
||||
// 主集群
|
||||
var clusterMap maps.Map = nil
|
||||
if node.NodeCluster != nil {
|
||||
var clusterId = node.NodeCluster.Id
|
||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: clusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var cluster = clusterResp.NodeCluster
|
||||
if cluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"installDir": cluster.InstallDir,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 从集群
|
||||
var secondaryClustersMaps = []maps.Map{}
|
||||
for _, cluster := range node.SecondaryNodeClusters {
|
||||
secondaryClustersMaps = append(secondaryClustersMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"isOn": cluster.IsOn,
|
||||
})
|
||||
}
|
||||
|
||||
// 当前访问集群的DNS设置
|
||||
clusterDNSInfo, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["dnsIsExcludingLnNode"] = clusterDNSInfo != nil && !clusterDNSInfo.IncludingLnNodes && node.Level > 1
|
||||
|
||||
// IP地址
|
||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var ipAddresses = ipAddressesResp.NodeIPAddresses
|
||||
var ipAddressMaps = []maps.Map{}
|
||||
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
||||
thresholds, err := ipaddressutils.InitNodeIPAddressThresholds(this.Parent(), addr.Id)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 是否有备用IP
|
||||
var originIP = addr.Ip
|
||||
if len(addr.BackupIP) > 0 {
|
||||
addr.Ip = addr.BackupIP
|
||||
}
|
||||
|
||||
// 专属集群
|
||||
var addrClusterMaps = []maps.Map{}
|
||||
for _, addrCluster := range addr.NodeClusters {
|
||||
addrClusterMaps = append(addrClusterMaps, maps.Map{
|
||||
"id": addrCluster.Id,
|
||||
"name": addrCluster.Name,
|
||||
})
|
||||
}
|
||||
|
||||
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
||||
"id": addr.Id,
|
||||
"name": addr.Name,
|
||||
"originIP": originIP,
|
||||
"ip": addr.Ip,
|
||||
"canAccess": addr.CanAccess,
|
||||
"isOn": addr.IsOn,
|
||||
"isUp": addr.IsUp,
|
||||
"clusters": addrClusterMaps,
|
||||
"thresholds": thresholds,
|
||||
})
|
||||
}
|
||||
|
||||
// DNS相关
|
||||
var clusters = []*pb.NodeCluster{node.NodeCluster}
|
||||
clusters = append(clusters, node.SecondaryNodeClusters...)
|
||||
var recordMaps = []maps.Map{}
|
||||
var routeMaps = []maps.Map{}
|
||||
for _, cluster := range clusters {
|
||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeClusterId: cluster.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var dnsInfo = dnsInfoResp.Node
|
||||
if len(dnsInfo.DnsDomainName) == 0 || len(dnsInfo.NodeClusterDNSName) == 0 {
|
||||
continue
|
||||
}
|
||||
var domainName = dnsInfo.DnsDomainName
|
||||
|
||||
// 默认线路
|
||||
if len(dnsInfo.Routes) == 0 {
|
||||
dnsInfo.Routes = append(dnsInfo.Routes, &pb.DNSRoute{})
|
||||
} else {
|
||||
for _, route := range dnsInfo.Routes {
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"domainName": domainName,
|
||||
"code": route.Code,
|
||||
"name": route.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, addr := range ipAddresses {
|
||||
if !addr.CanAccess || !addr.IsUp || !addr.IsOn {
|
||||
continue
|
||||
}
|
||||
|
||||
// 过滤集群
|
||||
if len(addr.NodeClusters) > 0 {
|
||||
var inCluster = false
|
||||
for _, addrCluster := range addr.NodeClusters {
|
||||
if addrCluster.Id == cluster.Id {
|
||||
inCluster = true
|
||||
}
|
||||
}
|
||||
if !inCluster {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for _, route := range dnsInfo.Routes {
|
||||
var recordType = "A"
|
||||
if iputils.IsIPv6(addr.Ip) {
|
||||
recordType = "AAAA"
|
||||
}
|
||||
recordMaps = append(recordMaps, maps.Map{
|
||||
"name": dnsInfo.NodeClusterDNSName + "." + domainName,
|
||||
"type": recordType,
|
||||
"route": route.Name,
|
||||
"value": addr.Ip,
|
||||
"clusterName": cluster.Name,
|
||||
"isBackup": dnsInfo.IsBackupForCluster || dnsInfo.IsBackupForGroup,
|
||||
"isOffline": dnsInfo.IsOffline,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 登录信息
|
||||
var loginMap maps.Map = nil
|
||||
if node.NodeLogin != nil {
|
||||
loginParams := maps.Map{}
|
||||
if len(node.NodeLogin.Params) > 0 {
|
||||
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var grantMap = maps.Map{}
|
||||
var grantId = loginParams.GetInt64("grantId")
|
||||
if grantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.NodeGrant != nil {
|
||||
grantMap = maps.Map{
|
||||
"id": grantResp.NodeGrant.Id,
|
||||
"name": grantResp.NodeGrant.Name,
|
||||
"method": grantResp.NodeGrant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method, this.LangCode()),
|
||||
"username": grantResp.NodeGrant.Username,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loginMap = maps.Map{
|
||||
"id": node.NodeLogin.Id,
|
||||
"name": node.NodeLogin.Name,
|
||||
"type": node.NodeLogin.Type,
|
||||
"params": loginParams,
|
||||
"grant": grantMap,
|
||||
}
|
||||
}
|
||||
|
||||
// 运行状态
|
||||
var status = &nodeconfigs.NodeStatus{}
|
||||
this.Data["nodeDatetime"] = ""
|
||||
this.Data["nodeTimeDiff"] = 0
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||
|
||||
if status.Timestamp > 0 {
|
||||
this.Data["nodeDatetime"] = timeutil.FormatTime("Y-m-d H:i:s", status.Timestamp)
|
||||
if status.UpdatedAt > 0 {
|
||||
var diff = status.UpdatedAt - status.Timestamp
|
||||
if diff < 0 {
|
||||
diff = -diff
|
||||
}
|
||||
this.Data["nodeTimeDiff"] = diff
|
||||
}
|
||||
} else if status.UpdatedAt > 0 {
|
||||
this.Data["nodeDatetime"] = timeutil.FormatTime("Y-m-d H:i:s", status.UpdatedAt)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否有新版本
|
||||
if len(status.OS) > 0 {
|
||||
checkVersionResp, err := this.RPC().NodeRPC().CheckNodeLatestVersion(this.AdminContext(), &pb.CheckNodeLatestVersionRequest{
|
||||
Os: status.OS,
|
||||
Arch: status.Arch,
|
||||
CurrentVersion: status.BuildVersion,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["shouldUpgrade"] = checkVersionResp.HasNewVersion
|
||||
this.Data["newVersion"] = checkVersionResp.NewVersion
|
||||
} else {
|
||||
this.Data["shouldUpgrade"] = false
|
||||
this.Data["newVersion"] = ""
|
||||
}
|
||||
|
||||
// 分组
|
||||
var groupMap maps.Map = nil
|
||||
if node.NodeGroup != nil {
|
||||
groupMap = maps.Map{
|
||||
"id": node.NodeGroup.Id,
|
||||
"name": node.NodeGroup.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// 区域
|
||||
var regionMap maps.Map = nil
|
||||
if node.NodeRegion != nil {
|
||||
regionMap = maps.Map{
|
||||
"id": node.NodeRegion.Id,
|
||||
"name": node.NodeRegion.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存硬盘 & 内存容量
|
||||
var maxCacheDiskCapacity maps.Map
|
||||
if node.MaxCacheDiskCapacity != nil {
|
||||
maxCacheDiskCapacity = maps.Map{
|
||||
"count": node.MaxCacheDiskCapacity.Count,
|
||||
"unit": node.MaxCacheDiskCapacity.Unit,
|
||||
}
|
||||
} else {
|
||||
maxCacheDiskCapacity = maps.Map{
|
||||
"count": 0,
|
||||
"unit": "gb",
|
||||
}
|
||||
}
|
||||
|
||||
var maxCacheMemoryCapacity maps.Map
|
||||
if node.MaxCacheMemoryCapacity != nil {
|
||||
maxCacheMemoryCapacity = maps.Map{
|
||||
"count": node.MaxCacheMemoryCapacity.Count,
|
||||
"unit": node.MaxCacheMemoryCapacity.Unit,
|
||||
}
|
||||
} else {
|
||||
maxCacheMemoryCapacity = maps.Map{
|
||||
"count": 0,
|
||||
"unit": "gb",
|
||||
}
|
||||
}
|
||||
|
||||
var lnAddrs = node.LnAddrs
|
||||
if lnAddrs == nil {
|
||||
lnAddrs = []string{}
|
||||
}
|
||||
|
||||
// API节点地址
|
||||
var apiNodeAddrStrings = []string{}
|
||||
var apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
if len(node.ApiNodeAddrsJSON) > 0 {
|
||||
err = json.Unmarshal(node.ApiNodeAddrsJSON, &apiNodeAddrs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, addr := range apiNodeAddrs {
|
||||
if addr.Init() == nil {
|
||||
apiNodeAddrStrings = append(apiNodeAddrStrings, addr.FullAddresses()...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddresses": ipAddressMaps,
|
||||
"cluster": clusterMap,
|
||||
"secondaryClusters": secondaryClustersMaps,
|
||||
"login": loginMap,
|
||||
"installDir": node.InstallDir,
|
||||
"isInstalled": node.IsInstalled,
|
||||
"uniqueId": node.UniqueId,
|
||||
"secret": node.Secret,
|
||||
"maxCPU": node.MaxCPU,
|
||||
"isOn": node.IsOn,
|
||||
"records": recordMaps,
|
||||
"routes": routeMaps,
|
||||
"level": node.Level,
|
||||
"levelInfo": nodeconfigs.FindNodeLevel(int(node.Level)),
|
||||
"lnAddrs": lnAddrs,
|
||||
"enableIPLists": node.EnableIPLists,
|
||||
"apiNodeAddrs": apiNodeAddrStrings,
|
||||
"offlineDay": node.OfflineDay,
|
||||
"isOffline": len(node.OfflineDay) > 0 && node.OfflineDay < timeutil.Format("Ymd"),
|
||||
"isBackupForCluster": node.IsBackupForCluster,
|
||||
"isBackupForGroup": node.IsBackupForGroup,
|
||||
|
||||
"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,
|
||||
"apiSuccessPercent": status.APISuccessPercent,
|
||||
"apiAvgCostSeconds": status.APIAvgCostSeconds,
|
||||
"diskWritingSpeedMB": status.DiskWritingSpeedMB,
|
||||
},
|
||||
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
|
||||
"maxCacheDiskCapacity": maxCacheDiskCapacity,
|
||||
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "node")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if teaconst.IsPlus {
|
||||
this.RedirectURL("/clusters/cluster/node/boards?clusterId=" + fmt.Sprintf("%d", this.Data["clusterId"]) + "&nodeId=" + strconv.FormatInt(params.NodeId, 10))
|
||||
} else {
|
||||
this.RedirectURL("/clusters/cluster/node/detail?clusterId=" + fmt.Sprintf("%d", this.Data["clusterId"]) + "&nodeId=" + strconv.FormatInt(params.NodeId, 10))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// InstallAction 安装节点
|
||||
type InstallAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *InstallAction) Init() {
|
||||
this.Nav("", "node", "install")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *InstallAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
// 节点
|
||||
node, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 最近运行目录
|
||||
var exeRoot = ""
|
||||
if len(node.StatusJSON) > 0 {
|
||||
var nodeStatus = &nodeconfigs.NodeStatus{}
|
||||
err = json.Unmarshal(node.StatusJSON, nodeStatus)
|
||||
if err == nil {
|
||||
var exePath = nodeStatus.ExePath
|
||||
if len(exePath) > 0 {
|
||||
exeRoot = filepath.Dir(filepath.Dir(exePath))
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["exeRoot"] = exeRoot
|
||||
|
||||
// 安装信息
|
||||
if node.InstallStatus != nil {
|
||||
this.Data["installStatus"] = maps.Map{
|
||||
"isRunning": node.InstallStatus.IsRunning,
|
||||
"isFinished": node.InstallStatus.IsFinished,
|
||||
"isOk": node.InstallStatus.IsOk,
|
||||
"updatedAt": node.InstallStatus.UpdatedAt,
|
||||
"error": node.InstallStatus.Error,
|
||||
}
|
||||
} else {
|
||||
this.Data["installStatus"] = nil
|
||||
}
|
||||
|
||||
// 集群
|
||||
var clusterMap maps.Map = nil
|
||||
if node.NodeCluster != nil {
|
||||
clusterId := node.NodeCluster.Id
|
||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: clusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cluster := clusterResp.NodeCluster
|
||||
if cluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"installDir": cluster.InstallDir,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// API节点列表
|
||||
apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var apiNodes = apiNodesResp.ApiNodes
|
||||
apiEndpoints := []string{}
|
||||
for _, apiNode := range apiNodes {
|
||||
if !apiNode.IsOn {
|
||||
continue
|
||||
}
|
||||
apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...)
|
||||
}
|
||||
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
||||
|
||||
var nodeMap = this.Data["node"].(maps.Map)
|
||||
nodeMap["installDir"] = node.InstallDir
|
||||
nodeMap["isInstalled"] = node.IsInstalled
|
||||
nodeMap["uniqueId"] = node.UniqueId
|
||||
nodeMap["secret"] = node.Secret
|
||||
nodeMap["cluster"] = clusterMap
|
||||
|
||||
// 安装文件
|
||||
var installerFiles = clusterutils.ListInstallerFiles()
|
||||
this.Data["installerFiles"] = installerFiles
|
||||
|
||||
// SSH主机地址
|
||||
this.Data["sshAddr"] = ""
|
||||
if node.NodeLogin != nil && node.NodeLogin.Type == "ssh" && !utils.JSONIsNull(node.NodeLogin.Params) {
|
||||
var loginParams = maps.Map{}
|
||||
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var host = loginParams.GetString("host")
|
||||
if len(host) > 0 {
|
||||
var port = loginParams.GetString("port")
|
||||
if port == "0" {
|
||||
port = "22"
|
||||
}
|
||||
this.Data["sshAddr"] = configutils.QuoteIP(host) + ":" + port
|
||||
}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
// RunPost 开始安装
|
||||
func (this *InstallAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
_, err := this.RPC().NodeRPC().InstallNode(this.AdminContext(), &pb.InstallNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogInstallNode, params.NodeId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/nodelogutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"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
|
||||
Tag string
|
||||
}) {
|
||||
// 初始化节点信息(用于菜单)
|
||||
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["tags"] = nodelogutils.FindNodeCommonTags(this.LangCode())
|
||||
|
||||
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
|
||||
this.Data["tag"] = params.Tag
|
||||
|
||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
NodeId: params.NodeId,
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
Tag: params.Tag,
|
||||
})
|
||||
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: "node",
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
Tag: params.Tag,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
logs := []maps.Map{}
|
||||
for _, log := range logsResp.NodeLogs {
|
||||
// 服务信息
|
||||
var serverMap = maps.Map{"id": 0}
|
||||
if log.ServerId > 0 {
|
||||
serverResp, err := this.RPC().ServerRPC().FindEnabledUserServerBasic(this.AdminContext(), &pb.FindEnabledUserServerBasicRequest{ServerId: log.ServerId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var server = serverResp.Server
|
||||
if server != nil {
|
||||
serverMap = maps.Map{"id": server.Id, "name": server.Name}
|
||||
}
|
||||
}
|
||||
|
||||
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"),
|
||||
"count": log.Count,
|
||||
"server": serverMap,
|
||||
})
|
||||
}
|
||||
this.Data["logs"] = logs
|
||||
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package nodeutils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// InitNodeInfo 初始化节点信息
|
||||
func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Node, error) {
|
||||
// 节点信息(用于菜单)
|
||||
nodeResp, err := parentAction.RPC().NodeRPC().FindEnabledNode(parentAction.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: nodeId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nodeResp.Node == nil {
|
||||
return nil, errors.New("node '" + strconv.FormatInt(nodeId, 10) + "' not found")
|
||||
}
|
||||
var node = nodeResp.Node
|
||||
|
||||
info, err := parentAction.RPC().NodeRPC().FindEnabledNodeConfigInfo(parentAction.AdminContext(), &pb.FindEnabledNodeConfigInfoRequest{NodeId: nodeId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var groupMap maps.Map
|
||||
if node.NodeGroup != nil {
|
||||
groupMap = maps.Map{
|
||||
"id": node.NodeGroup.Id,
|
||||
"name": node.NodeGroup.Name,
|
||||
}
|
||||
}
|
||||
|
||||
parentAction.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"isOn": node.IsOn,
|
||||
"isUp": node.IsUp,
|
||||
"group": groupMap,
|
||||
"level": node.Level,
|
||||
}
|
||||
var clusterId int64 = 0
|
||||
if node.NodeCluster != nil {
|
||||
parentAction.Data["clusterId"] = node.NodeCluster.Id
|
||||
clusterId = node.NodeCluster.Id
|
||||
}
|
||||
|
||||
// 左侧菜单
|
||||
var prefix = "/clusters/cluster/node"
|
||||
var query = "clusterId=" + types.String(clusterId) + "&nodeId=" + types.String(nodeId)
|
||||
var menuItem = parentAction.Data.GetString("secondMenuItem")
|
||||
|
||||
var menuItems = []maps.Map{
|
||||
{
|
||||
"name": parentAction.Lang(codes.NodeMenu_SettingBasic),
|
||||
"url": prefix + "/update?" + query,
|
||||
"isActive": menuItem == "basic",
|
||||
},
|
||||
{
|
||||
"name": parentAction.Lang(codes.NodeMenu_SettingDNS),
|
||||
"url": prefix + "/settings/dns?" + query,
|
||||
"isActive": menuItem == "dns",
|
||||
"isOn": info.HasDNSInfo,
|
||||
},
|
||||
{
|
||||
"name": parentAction.Lang(codes.NodeMenu_SettingCache),
|
||||
"url": prefix + "/settings/cache?" + query,
|
||||
"isActive": menuItem == "cache",
|
||||
"isOn": info.HasCacheInfo,
|
||||
},
|
||||
{
|
||||
"name": parentAction.Lang(codes.NodeMenu_SettingDDoSProtection),
|
||||
"url": prefix + "/settings/ddos-protection?" + query,
|
||||
"isActive": menuItem == "ddosProtection",
|
||||
"isOn": info.HasDDoSProtection,
|
||||
},
|
||||
{
|
||||
"name": "-",
|
||||
"url": "",
|
||||
},
|
||||
}
|
||||
menuItems = filterMenuItems(menuItems, menuItem, prefix, query, info, parentAction.LangCode())
|
||||
menuItems = append(menuItems, []maps.Map{
|
||||
{
|
||||
"name": parentAction.Lang(codes.NodeMenu_SettingSSH),
|
||||
"url": prefix + "/settings/ssh?" + query,
|
||||
"isActive": menuItem == "ssh",
|
||||
"isOn": info.HasSSH,
|
||||
},
|
||||
{
|
||||
"name": parentAction.Lang(codes.NodeMenu_SettingSystem),
|
||||
"url": prefix + "/settings/system?" + query,
|
||||
"isActive": menuItem == "system",
|
||||
"isOn": info.HasSystemSettings,
|
||||
},
|
||||
}...)
|
||||
parentAction.Data["leftMenuItems"] = menuItems
|
||||
|
||||
return nodeResp.Node, nil
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
|
||||
package nodeutils
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
func filterMenuItems(menuItems []maps.Map, menuItem string, prefix string, query string, info *pb.FindEnabledNodeConfigInfoResponse, langCode string) []maps.Map {
|
||||
return menuItems
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package nodeutils
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
plusutils "github.com/TeaOSLab/EdgePlus/pkg/utils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
func filterMenuItems(menuItems []maps.Map, menuItem string, prefix string, query string, info *pb.FindEnabledNodeConfigInfoResponse, langCode string) []maps.Map {
|
||||
if teaconst.IsPlus {
|
||||
if plusutils.CheckComponent(plusutils.ComponentCodeScheduling) {
|
||||
menuItems = append(menuItems, maps.Map{
|
||||
"name": langs.Message(langCode, codes.NodeMenu_SettingSchedule),
|
||||
"url": prefix + "/settings/schedule?" + query,
|
||||
"isActive": menuItem == "schedule",
|
||||
"isOn": info.HasScheduleSettings,
|
||||
})
|
||||
}
|
||||
menuItems = append(menuItems, []maps.Map{
|
||||
{
|
||||
"name": langs.Message(langCode, codes.NodeMenu_SettingThresholds),
|
||||
"url": prefix + "/settings/thresholds?" + query,
|
||||
"isActive": menuItem == "threshold",
|
||||
"isOn": info.HasThresholds,
|
||||
},
|
||||
}...)
|
||||
}
|
||||
return menuItems
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package nodeutils_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInstallLocalNode(t *testing.T) {
|
||||
err := nodeutils.InstallLocalNode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
143
EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/cache/index.go
vendored
Normal file
143
EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/cache/index.go
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("cache")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
node, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 缓存硬盘 & 内存容量
|
||||
var maxCacheDiskCapacity maps.Map
|
||||
if node.MaxCacheDiskCapacity != nil {
|
||||
maxCacheDiskCapacity = maps.Map{
|
||||
"count": node.MaxCacheDiskCapacity.Count,
|
||||
"unit": node.MaxCacheDiskCapacity.Unit,
|
||||
}
|
||||
} else {
|
||||
maxCacheDiskCapacity = maps.Map{
|
||||
"count": 0,
|
||||
"unit": "gb",
|
||||
}
|
||||
}
|
||||
|
||||
var maxCacheMemoryCapacity maps.Map
|
||||
if node.MaxCacheMemoryCapacity != nil {
|
||||
maxCacheMemoryCapacity = maps.Map{
|
||||
"count": node.MaxCacheMemoryCapacity.Count,
|
||||
"unit": node.MaxCacheMemoryCapacity.Unit,
|
||||
}
|
||||
} else {
|
||||
maxCacheMemoryCapacity = maps.Map{
|
||||
"count": 0,
|
||||
"unit": "gb",
|
||||
}
|
||||
}
|
||||
|
||||
var diskSubDirs = []*serverconfigs.CacheDir{}
|
||||
if len(node.CacheDiskSubDirsJSON) > 0 {
|
||||
err = json.Unmarshal(node.CacheDiskSubDirsJSON, &diskSubDirs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var nodeMap = this.Data["node"].(maps.Map)
|
||||
nodeMap["maxCacheDiskCapacity"] = maxCacheDiskCapacity
|
||||
nodeMap["cacheDiskDir"] = node.CacheDiskDir
|
||||
nodeMap["cacheDiskSubDirs"] = diskSubDirs
|
||||
nodeMap["maxCacheMemoryCapacity"] = maxCacheMemoryCapacity
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
MaxCacheDiskCapacityJSON []byte
|
||||
CacheDiskDir string
|
||||
CacheDiskSubDirsJSON []byte
|
||||
MaxCacheMemoryCapacityJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeCache_LogUpdateNodeCacheSettings, params.NodeId)
|
||||
|
||||
// 缓存硬盘 & 内存容量
|
||||
var pbMaxCacheDiskCapacity *pb.SizeCapacity
|
||||
if len(params.MaxCacheDiskCapacityJSON) > 0 {
|
||||
var sizeCapacity = &shared.SizeCapacity{}
|
||||
err := json.Unmarshal(params.MaxCacheDiskCapacityJSON, sizeCapacity)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
pbMaxCacheDiskCapacity = &pb.SizeCapacity{
|
||||
Count: sizeCapacity.Count,
|
||||
Unit: sizeCapacity.Unit,
|
||||
}
|
||||
}
|
||||
|
||||
var pbMaxCacheMemoryCapacity *pb.SizeCapacity
|
||||
if len(params.MaxCacheMemoryCapacityJSON) > 0 {
|
||||
var sizeCapacity = &shared.SizeCapacity{}
|
||||
err := json.Unmarshal(params.MaxCacheMemoryCapacityJSON, sizeCapacity)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
pbMaxCacheMemoryCapacity = &pb.SizeCapacity{
|
||||
Count: sizeCapacity.Count,
|
||||
Unit: sizeCapacity.Unit,
|
||||
}
|
||||
}
|
||||
|
||||
if len(params.CacheDiskSubDirsJSON) > 0 {
|
||||
var cacheSubDirs = []*serverconfigs.CacheDir{}
|
||||
err := json.Unmarshal(params.CacheDiskSubDirsJSON, &cacheSubDirs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeCache(this.AdminContext(), &pb.UpdateNodeCacheRequest{
|
||||
NodeId: params.NodeId,
|
||||
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
||||
CacheDiskDir: params.CacheDiskDir,
|
||||
CacheDiskSubDirsJSON: params.CacheDiskSubDirsJSON,
|
||||
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ddosProtection
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("ddosProtection")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
// 集群设置
|
||||
clusterProtectionResp, err := this.RPC().NodeClusterRPC().FindNodeClusterDDoSProtection(this.AdminContext(), &pb.FindNodeClusterDDoSProtectionRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var clusterDDoSProtectionIsOn = false
|
||||
if len(clusterProtectionResp.DdosProtectionJSON) > 0 {
|
||||
var clusterDDoSProtection = &ddosconfigs.ProtectionConfig{}
|
||||
err = json.Unmarshal(clusterProtectionResp.DdosProtectionJSON, clusterDDoSProtection)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
clusterDDoSProtectionIsOn = clusterDDoSProtection.IsOn()
|
||||
}
|
||||
|
||||
this.Data["clusterDDoSProtectionIsOn"] = clusterDDoSProtectionIsOn
|
||||
|
||||
// 节点设置
|
||||
ddosProtectionResp, err := this.RPC().NodeRPC().FindNodeDDoSProtection(this.AdminContext(), &pb.FindNodeDDoSProtectionRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var ddosProtectionConfig = ddosconfigs.DefaultProtectionConfig()
|
||||
if len(ddosProtectionResp.DdosProtectionJSON) > 0 {
|
||||
err = json.Unmarshal(ddosProtectionResp.DdosProtectionJSON, ddosProtectionConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["config"] = ddosProtectionConfig
|
||||
this.Data["defaultConfigs"] = nodeconfigs.DefaultConfigs
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
DdosProtectionJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.DDoSProtection_LogUpdateNodeDDoSProtection, params.NodeId)
|
||||
|
||||
var ddosProtectionConfig = &ddosconfigs.ProtectionConfig{}
|
||||
err := json.Unmarshal(params.DdosProtectionJSON, ddosProtectionConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = ddosProtectionConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
// 校验参数
|
||||
if ddosProtectionConfig.TCP != nil {
|
||||
var tcpConfig = ddosProtectionConfig.TCP
|
||||
if tcpConfig.MaxConnectionsPerIP > 0 && tcpConfig.MaxConnectionsPerIP < nodeconfigs.DefaultTCPMinConnectionsPerIP {
|
||||
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
||||
}
|
||||
|
||||
if tcpConfig.NewConnectionsMinutelyRate > 0 && tcpConfig.NewConnectionsMinutelyRate < nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate {
|
||||
this.FailField("tcpNewConnectionsMinutelyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate))
|
||||
}
|
||||
|
||||
if tcpConfig.NewConnectionsSecondlyRate > 0 && tcpConfig.NewConnectionsSecondlyRate < nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate {
|
||||
this.FailField("tcpNewConnectionsSecondlyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate))
|
||||
}
|
||||
|
||||
// Port
|
||||
for _, portConfig := range tcpConfig.Ports {
|
||||
if portConfig.Port > 65535 {
|
||||
this.Fail("端口号" + types.String(portConfig.Port) + "不能大于65535")
|
||||
}
|
||||
}
|
||||
|
||||
// IP
|
||||
for _, ipConfig := range tcpConfig.AllowIPList {
|
||||
if net.ParseIP(ipConfig.IP) == nil {
|
||||
this.Fail("白名单IP '" + ipConfig.IP + "' 格式错误")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeRPC().UpdateNodeDDoSProtection(this.AdminContext(), &pb.UpdateNodeDDoSProtectionRequest{
|
||||
NodeId: params.NodeId,
|
||||
DdosProtectionJSON: params.DdosProtectionJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ddosProtection
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
)
|
||||
|
||||
type StatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
results, err := nodeutils.SendMessageToNodeIds(this.AdminContext(), []int64{params.NodeId}, messageconfigs.MessageCodeCheckLocalFirewall, &messageconfigs.CheckLocalFirewallMessage{
|
||||
Name: "nftables",
|
||||
}, 10)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["results"] = results
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("dns")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
node, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// DNS相关
|
||||
var clusters = []*pb.NodeCluster{node.NodeCluster}
|
||||
clusters = append(clusters, node.SecondaryNodeClusters...)
|
||||
var allDNSRouteMaps = map[int64][]maps.Map{} // domain id => routes
|
||||
var routeMaps = map[int64][]maps.Map{} // domain id => routes
|
||||
var domainIds = []int64{}
|
||||
for _, cluster := range clusters {
|
||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeClusterId: cluster.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var dnsInfo = dnsInfoResp.Node
|
||||
if dnsInfo.DnsDomainId <= 0 || len(dnsInfo.DnsDomainName) == 0 {
|
||||
continue
|
||||
}
|
||||
var domainId = dnsInfo.DnsDomainId
|
||||
|
||||
// remove same domain
|
||||
if lists.ContainsInt64(domainIds, domainId) {
|
||||
continue
|
||||
}
|
||||
domainIds = append(domainIds, domainId)
|
||||
|
||||
var domainName = dnsInfo.DnsDomainName
|
||||
if len(dnsInfo.Routes) > 0 {
|
||||
for _, route := range dnsInfo.Routes {
|
||||
routeMaps[domainId] = append(routeMaps[domainId], maps.Map{
|
||||
"domainId": domainId,
|
||||
"domainName": domainName,
|
||||
"code": route.Code,
|
||||
"name": route.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 所有线路选项
|
||||
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: dnsInfoResp.Node.DnsDomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, route := range routesResp.Routes {
|
||||
allDNSRouteMaps[domainId] = append(allDNSRouteMaps[domainId], maps.Map{
|
||||
"domainId": domainId,
|
||||
"domainName": domainName,
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var domainRoutes = []maps.Map{}
|
||||
for _, m := range routeMaps {
|
||||
domainRoutes = append(domainRoutes, m...)
|
||||
}
|
||||
this.Data["dnsRoutes"] = domainRoutes
|
||||
|
||||
var allDomainRoutes = []maps.Map{}
|
||||
for _, m := range allDNSRouteMaps {
|
||||
allDomainRoutes = append(allDomainRoutes, m...)
|
||||
}
|
||||
this.Data["allDNSRoutes"] = allDomainRoutes
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
DnsDomainId int64
|
||||
DnsRoutesJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeDNS_LogUpdateNodeDNS, params.NodeId)
|
||||
|
||||
var rawRouteCodes = []string{}
|
||||
if len(params.DnsRoutesJSON) > 0 {
|
||||
err := json.Unmarshal(params.DnsRoutesJSON, &rawRouteCodes)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplications
|
||||
var dnsRouteCodes = []string{}
|
||||
for _, routeCode := range rawRouteCodes {
|
||||
if !lists.ContainsString(dnsRouteCodes, routeCode) {
|
||||
dnsRouteCodes = append(dnsRouteCodes, routeCode)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeDNS(this.AdminContext(), &pb.UpdateNodeDNSRequest{
|
||||
NodeId: params.NodeId,
|
||||
IpAddr: "",
|
||||
DnsDomainId: 0,
|
||||
Routes: dnsRouteCodes,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package scheduleactions
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type CopyToClusterAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CopyToClusterAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeAction_LogCopyNodeActionsToCluster, params.NodeId)
|
||||
|
||||
_, err := this.RPC().NodeRPC().CopyNodeActionsToNodeCluster(this.AdminContext(), &pb.CopyNodeActionsToNodeClusterRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package scheduleactions
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type CopyToGroupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CopyToGroupAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeAction_LogCopyNodeActionsToGroup, params.NodeId)
|
||||
|
||||
_, err := this.RPC().NodeRPC().CopyNodeActionsToNodeGroup(this.AdminContext(), &pb.CopyNodeActionsToNodeGroupRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package scheduleactions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
// 选项
|
||||
this.Data["params"] = nodeconfigs.FindAllNodeActionParamDefinitions()
|
||||
this.Data["operators"] = nodeconfigs.FindAllNodeActionOperatorDefinitions()
|
||||
this.Data["actions"] = nodeconfigs.FindAllNodeActionDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
CondsJSON []byte
|
||||
ActionJSON []byte
|
||||
DurationMinutes int16
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var createdActionId int64
|
||||
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.NodeAction_LogCreateNodeAction, createdActionId)
|
||||
}()
|
||||
|
||||
// 校验条件
|
||||
if len(params.CondsJSON) == 0 {
|
||||
this.Fail("请设置条件")
|
||||
return
|
||||
}
|
||||
var condsConfig = &nodeconfigs.NodeActionCondsConfig{}
|
||||
err := json.Unmarshal(params.CondsJSON, condsConfig)
|
||||
if err != nil {
|
||||
this.Fail("条件解析错误:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 校验动作
|
||||
if len(params.ActionJSON) == 0 {
|
||||
this.Fail("请选择要执行的动作")
|
||||
return
|
||||
}
|
||||
var actionConfig = nodeconfigs.NewNodeActionConfig()
|
||||
err = json.Unmarshal(params.ActionJSON, actionConfig)
|
||||
if err != nil {
|
||||
this.Fail("动作解析错误:" + err.Error())
|
||||
return
|
||||
}
|
||||
if len(actionConfig.Code) == 0 {
|
||||
this.Fail("请选择要执行的动作")
|
||||
return
|
||||
}
|
||||
|
||||
// 校验动作参数
|
||||
switch actionConfig.Code {
|
||||
case nodeconfigs.NodeActionCodeWebHook:
|
||||
actionParamsJSON, err := json.Marshal(actionConfig.Params)
|
||||
if err != nil {
|
||||
this.Fail("解析WebHook参数失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
var actionParams = &nodeconfigs.NodeActionCodeWebHookParams{}
|
||||
err = json.Unmarshal(actionParamsJSON, actionParams)
|
||||
if err != nil {
|
||||
this.Fail("解析WebHook参数失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
if len(actionParams.URL) == 0 {
|
||||
this.Fail("请输入WebHook URL参数")
|
||||
return
|
||||
}
|
||||
if !regexp.MustCompile(`^(?i)(http|https)://`).MatchString(actionParams.URL) {
|
||||
this.Fail("请输入正确的WebHook URL参数")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 时间限制
|
||||
if params.DurationMinutes <= 0 {
|
||||
this.Fail("请输入持续时间")
|
||||
return
|
||||
}
|
||||
durationJSON, err := (&shared.TimeDuration{
|
||||
Count: types.Int64(params.DurationMinutes),
|
||||
Unit: shared.TimeDurationUnitMinute,
|
||||
}).AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().NodeActionRPC().CreateNodeAction(this.AdminContext(), &pb.CreateNodeActionRequest{
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
CondsJSON: params.CondsJSON,
|
||||
ActionJSON: params.ActionJSON,
|
||||
DurationJSON: durationJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
createdActionId = createResp.NodeActionId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package scheduleactions
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
ActionId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeAction_LogDeleteNodeAction, params.ActionId)
|
||||
|
||||
_, err := this.RPC().NodeActionRPC().DeleteNodeAction(this.AdminContext(), &pb.DeleteNodeActionRequest{NodeActionId: params.ActionId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package scheduleactions
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type UpdateActionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateActionsAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
ActionIds []int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeAction_LogSortNodeActions, params.NodeId)
|
||||
|
||||
if len(params.ActionIds) == 0 {
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeActionRPC().UpdateNodeActionOrders(this.AdminContext(), &pb.UpdateNodeActionOrdersRequest{NodeActionIds: params.ActionIds})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package scheduleactions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
ActionId int64
|
||||
}) {
|
||||
actionResp, err := this.RPC().NodeActionRPC().FindNodeAction(this.AdminContext(), &pb.FindNodeActionRequest{NodeActionId: params.ActionId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var action = actionResp.NodeAction
|
||||
if action == nil {
|
||||
this.NotFound("nodeAction", params.ActionId)
|
||||
return
|
||||
}
|
||||
|
||||
// 条件
|
||||
var condsConfig = &nodeconfigs.NodeActionCondsConfig{}
|
||||
err = json.Unmarshal(action.CondsJSON, condsConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 动作
|
||||
var actionConfig = nodeconfigs.NewNodeActionConfig()
|
||||
err = json.Unmarshal(action.ActionJSON, actionConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 时间
|
||||
var duration = &shared.TimeDuration{}
|
||||
if len(action.DurationJSON) > 0 {
|
||||
err = json.Unmarshal(action.DurationJSON, duration)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
var durationMinutes = duration.Seconds() / 60 // 目前只支持分钟
|
||||
|
||||
this.Data["action"] = maps.Map{
|
||||
"id": action.Id,
|
||||
"isOn": action.IsOn,
|
||||
"conds": condsConfig,
|
||||
"action": actionConfig,
|
||||
"durationMinutes": durationMinutes,
|
||||
}
|
||||
|
||||
// 选项
|
||||
this.Data["params"] = nodeconfigs.FindAllNodeActionParamDefinitions()
|
||||
this.Data["operators"] = nodeconfigs.FindAllNodeActionOperatorDefinitions()
|
||||
this.Data["actions"] = nodeconfigs.FindAllNodeActionDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
ActionId int64
|
||||
CondsJSON []byte
|
||||
ActionJSON []byte
|
||||
DurationMinutes int16
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeAction_LogUpdateNodeAction, params.ActionId)
|
||||
|
||||
// 校验条件
|
||||
if len(params.CondsJSON) == 0 {
|
||||
this.Fail("请设置条件")
|
||||
return
|
||||
}
|
||||
var condsConfig = &nodeconfigs.NodeActionCondsConfig{}
|
||||
err := json.Unmarshal(params.CondsJSON, condsConfig)
|
||||
if err != nil {
|
||||
this.Fail("条件解析错误:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 校验动作
|
||||
if len(params.ActionJSON) == 0 {
|
||||
this.Fail("请选择要执行的动作")
|
||||
return
|
||||
}
|
||||
var actionConfig = nodeconfigs.NewNodeActionConfig()
|
||||
err = json.Unmarshal(params.ActionJSON, actionConfig)
|
||||
if err != nil {
|
||||
this.Fail("动作解析错误:" + err.Error())
|
||||
return
|
||||
}
|
||||
if len(actionConfig.Code) == 0 {
|
||||
this.Fail("请选择要执行的动作")
|
||||
return
|
||||
}
|
||||
|
||||
// 校验动作参数
|
||||
switch actionConfig.Code {
|
||||
case nodeconfigs.NodeActionCodeWebHook:
|
||||
actionParamsJSON, err := json.Marshal(actionConfig.Params)
|
||||
if err != nil {
|
||||
this.Fail("解析WebHook参数失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
var actionParams = &nodeconfigs.NodeActionCodeWebHookParams{}
|
||||
err = json.Unmarshal(actionParamsJSON, actionParams)
|
||||
if err != nil {
|
||||
this.Fail("解析WebHook参数失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
if len(actionParams.URL) == 0 {
|
||||
this.Fail("请输入WebHook URL参数")
|
||||
return
|
||||
}
|
||||
if !regexp.MustCompile(`^(?i)(http|https)://`).MatchString(actionParams.URL) {
|
||||
this.Fail("请输入正确的WebHook URL参数")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 时间限制
|
||||
if params.DurationMinutes <= 0 {
|
||||
this.Fail("请输入持续时间")
|
||||
return
|
||||
}
|
||||
durationJSON, err := (&shared.TimeDuration{
|
||||
Count: types.Int64(params.DurationMinutes),
|
||||
Unit: shared.TimeDurationUnitMinute,
|
||||
}).AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeActionRPC().UpdateNodeAction(this.AdminContext(), &pb.UpdateNodeActionRequest{
|
||||
NodeActionId: params.ActionId,
|
||||
CondsJSON: params.CondsJSON,
|
||||
ActionJSON: params.ActionJSON,
|
||||
DurationJSON: durationJSON,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package nodeschedule
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("schedule")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
// 检查权限
|
||||
if !teaconst.IsPlus {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
// 基础设置
|
||||
scheduleInfoResp, err := this.RPC().NodeRPC().FindNodeScheduleInfo(this.AdminContext(), &pb.FindNodeScheduleInfoRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var scheduleInfo = scheduleInfoResp.ScheduleInfo
|
||||
if scheduleInfo == nil {
|
||||
this.NotFound("node", params.NodeId)
|
||||
return
|
||||
}
|
||||
|
||||
if len(scheduleInfo.OfflineDay) == 8 {
|
||||
scheduleInfo.OfflineDay = scheduleInfo.OfflineDay[:4] + "-" + scheduleInfo.OfflineDay[4:6] + "-" + scheduleInfo.OfflineDay[6:]
|
||||
}
|
||||
|
||||
if scheduleInfo.BackupIPs == nil {
|
||||
scheduleInfo.BackupIPs = []string{}
|
||||
}
|
||||
|
||||
// 当前节点所属集群
|
||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var node = nodeResp.Node
|
||||
if node == nil {
|
||||
this.NotFound("node", params.NodeId)
|
||||
return
|
||||
}
|
||||
var clusterName = ""
|
||||
if node.NodeCluster != nil {
|
||||
clusterName = node.NodeCluster.Name
|
||||
}
|
||||
|
||||
// 当前节点所属分组
|
||||
var groupName = ""
|
||||
if node.NodeGroup != nil {
|
||||
groupName = node.NodeGroup.Name
|
||||
}
|
||||
|
||||
// 动作状态
|
||||
var actionStatus = &nodeconfigs.NodeActionStatus{}
|
||||
if len(scheduleInfo.ActionStatusJSON) > 0 {
|
||||
err = json.Unmarshal(scheduleInfo.ActionStatusJSON, actionStatus)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
var actionStatusExpiresTime = ""
|
||||
if actionStatus.ExpiresAt > 0 {
|
||||
actionStatusExpiresTime = timeutil.FormatTime("Y-m-d H:i:s", actionStatus.ExpiresAt)
|
||||
}
|
||||
|
||||
this.Data["schedule"] = maps.Map{
|
||||
"id": params.NodeId,
|
||||
"offlineDay": scheduleInfo.OfflineDay,
|
||||
"isOffline": len(scheduleInfo.OfflineDay) > 0 && scheduleInfo.OfflineDay < timeutil.Format("Y-m-d" /** 前面的OfflineDay已经被转换 **/),
|
||||
"isNearlyOffline": len(scheduleInfo.OfflineDay) > 0 && scheduleInfo.OfflineDay < timeutil.Format("Y-m-d", time.Now().AddDate(0, 0, 3)),
|
||||
"isBackupForCluster": scheduleInfo.IsBackupForCluster,
|
||||
"isBackupForGroup": scheduleInfo.IsBackupForGroup,
|
||||
"backupIPs": scheduleInfo.BackupIPs,
|
||||
"nodeClusterName": clusterName,
|
||||
"nodeGroupName": groupName,
|
||||
"actionStatus": actionStatus,
|
||||
"actionStatusExpiresTime": actionStatusExpiresTime,
|
||||
}
|
||||
|
||||
// 所有动作
|
||||
actionsResp, err := this.RPC().NodeActionRPC().FindAllNodeActions(this.AdminContext(), &pb.FindAllNodeActionsRequest{
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var actionMaps = []maps.Map{}
|
||||
for _, action := range actionsResp.NodeActions {
|
||||
// conds
|
||||
var condsConfig = nodeconfigs.NewNodeActionCondsConfig()
|
||||
err = json.Unmarshal(action.CondsJSON, condsConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// action
|
||||
var actionConfig = nodeconfigs.NewNodeActionConfig()
|
||||
err = json.Unmarshal(action.ActionJSON, actionConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var actionDef = nodeconfigs.FindNodeActionDefinition(actionConfig.Code)
|
||||
if actionDef == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// duration
|
||||
var duration = &shared.TimeDuration{}
|
||||
if len(action.DurationJSON) > 0 {
|
||||
err = json.Unmarshal(action.DurationJSON, duration)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
var durationDescription = duration.Description()
|
||||
|
||||
// special durations
|
||||
for _, cond := range condsConfig.Conds {
|
||||
switch cond.Param {
|
||||
case nodeconfigs.NodeActionParamDailyTrafficOut:
|
||||
durationDescription = "当天"
|
||||
case nodeconfigs.NodeActionParamMonthlyTrafficOut:
|
||||
durationDescription = "当月"
|
||||
}
|
||||
}
|
||||
|
||||
actionMaps = append(actionMaps, maps.Map{
|
||||
"id": action.Id,
|
||||
"conds": condsConfig,
|
||||
"action": actionConfig,
|
||||
"actionName": actionDef.Name,
|
||||
"durationDescription": durationDescription,
|
||||
"isOn": action.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["actions"] = actionMaps
|
||||
|
||||
// 选项
|
||||
this.Data["params"] = nodeconfigs.FindAllNodeActionParamDefinitions()
|
||||
this.Data["operators"] = nodeconfigs.FindAllNodeActionOperatorDefinitions()
|
||||
|
||||
var actionMap = map[string]*shared.Definition{} // code => name
|
||||
for _, actionDef := range nodeconfigs.FindAllNodeActionDefinitions() {
|
||||
actionMap[actionDef.Code] = actionDef
|
||||
}
|
||||
this.Data["actionMap"] = actionMap
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
OfflineDay string
|
||||
IsBackupForCluster bool
|
||||
IsBackupForGroup bool
|
||||
BackupIPs []string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeSchedule_LogUpdateNodeScheduleBasic)
|
||||
|
||||
// 校验参数
|
||||
if len(params.OfflineDay) > 0 {
|
||||
if !regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`).MatchString(params.OfflineDay) {
|
||||
this.Fail("租期结束日期格式错误")
|
||||
return
|
||||
}
|
||||
params.OfflineDay = strings.ReplaceAll(params.OfflineDay, "-", "")
|
||||
}
|
||||
|
||||
for _, backupIP := range params.BackupIPs {
|
||||
if net.ParseIP(backupIP) == nil {
|
||||
this.Fail("备用IP '" + backupIP + "' IP错误")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeScheduleInfo(this.AdminContext(), &pb.UpdateNodeScheduleInfoRequest{
|
||||
NodeId: params.NodeId,
|
||||
OfflineDay: params.OfflineDay,
|
||||
IsBackupForCluster: params.IsBackupForCluster,
|
||||
IsBackupForGroup: params.IsBackupForGroup,
|
||||
BackupIPs: params.BackupIPs,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package nodeschedule
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type ResetActionStatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ResetActionStatusAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeSchedule_LogResetNodeActionStatus, params.NodeId)
|
||||
|
||||
_, err := this.RPC().NodeRPC().ResetNodeActionStatus(this.AdminContext(), &pb.ResetNodeActionStatusRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("ssh")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
node, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["hostIsAutoFilled"] = false
|
||||
|
||||
// 登录信息
|
||||
var loginMap maps.Map = nil
|
||||
if node.NodeLogin != nil {
|
||||
var loginParams = maps.Map{}
|
||||
if len(node.NodeLogin.Params) > 0 {
|
||||
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var grantMap = maps.Map{}
|
||||
var grantId = loginParams.GetInt64("grantId")
|
||||
if grantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.NodeGrant != nil {
|
||||
grantMap = maps.Map{
|
||||
"id": grantResp.NodeGrant.Id,
|
||||
"name": grantResp.NodeGrant.Name,
|
||||
"method": grantResp.NodeGrant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method, this.LangCode()),
|
||||
"username": grantResp.NodeGrant.Username,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loginMap = maps.Map{
|
||||
"id": node.NodeLogin.Id,
|
||||
"name": node.NodeLogin.Name,
|
||||
"type": node.NodeLogin.Type,
|
||||
"params": loginParams,
|
||||
"grant": grantMap,
|
||||
}
|
||||
}
|
||||
|
||||
if loginMap == nil {
|
||||
addressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{NodeId: node.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(addressesResp.NodeIPAddresses) > 0 {
|
||||
this.Data["hostIsAutoFilled"] = true
|
||||
loginMap = maps.Map{
|
||||
"id": 0,
|
||||
"name": "",
|
||||
"type": "ssh",
|
||||
"params": maps.Map{
|
||||
"host": addressesResp.NodeIPAddresses[0].Ip,
|
||||
"port": 22,
|
||||
"grantId": 0,
|
||||
},
|
||||
"grant": nil,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var loginParams = loginMap.GetMap("params")
|
||||
if len(loginParams.GetString("host")) == 0 {
|
||||
addressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{NodeId: node.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(addressesResp.NodeIPAddresses) > 0 {
|
||||
this.Data["hostIsAutoFilled"] = true
|
||||
loginParams["host"] = addressesResp.NodeIPAddresses[0].Ip
|
||||
}
|
||||
}
|
||||
|
||||
if loginParams.GetInt("port") == 0 {
|
||||
loginParams["port"] = 22
|
||||
}
|
||||
|
||||
loginMap["params"] = loginParams
|
||||
}
|
||||
|
||||
var nodeMap = this.Data["node"].(maps.Map)
|
||||
nodeMap["login"] = loginMap
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
|
||||
LoginId int64
|
||||
GrantId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeSSH_LogUpdateNodeSSH, params.NodeId)
|
||||
|
||||
// 检查IP地址
|
||||
if regexp.MustCompile(`^\d+\.\d+\.\d+\.\d+$`).MatchString(params.SshHost) && net.ParseIP(params.SshHost) == nil {
|
||||
this.Fail("SSH主机地址 '" + params.SshHost + "' IP格式错误")
|
||||
}
|
||||
|
||||
// TODO 检查登录授权
|
||||
var loginInfo = &pb.NodeLogin{
|
||||
Id: params.LoginId,
|
||||
Name: "SSH",
|
||||
Type: "ssh",
|
||||
Params: maps.Map{
|
||||
"grantId": params.GrantId,
|
||||
"host": params.SshHost,
|
||||
"port": params.SshPort,
|
||||
}.AsJSON(),
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeLogin(this.AdminContext(), &pb.UpdateNodeLoginRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeLogin: loginInfo,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
GrantId int64
|
||||
Host string
|
||||
Port int32
|
||||
}) {
|
||||
resp, err := this.RPC().NodeGrantRPC().TestNodeGrant(this.AdminContext(), &pb.TestNodeGrantRequest{
|
||||
NodeGrantId: params.GrantId,
|
||||
Host: params.Host,
|
||||
Port: params.Port,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["isOk"] = resp.IsOk
|
||||
this.Data["error"] = resp.Error
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("system")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
node, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取节点信息
|
||||
var nodeMap = this.Data["node"].(maps.Map)
|
||||
nodeMap["maxCPU"] = node.MaxCPU
|
||||
|
||||
// DNS
|
||||
dnsResolverResp, err := this.RPC().NodeRPC().FindNodeDNSResolver(this.AdminContext(), &pb.FindNodeDNSResolverRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var dnsResolverConfig = nodeconfigs.DefaultDNSResolverConfig()
|
||||
if len(dnsResolverResp.DnsResolverJSON) > 0 {
|
||||
err = json.Unmarshal(dnsResolverResp.DnsResolverJSON, dnsResolverConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["dnsResolverConfig"] = dnsResolverConfig
|
||||
|
||||
// API相关
|
||||
apiConfigResp, err := this.RPC().NodeRPC().FindNodeAPIConfig(this.AdminContext(), &pb.FindNodeAPIConfigRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
if len(apiConfigResp.ApiNodeAddrsJSON) > 0 {
|
||||
err = json.Unmarshal(apiConfigResp.ApiNodeAddrsJSON, &apiNodeAddrs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["apiNodeAddrs"] = apiNodeAddrs
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
MaxCPU int32
|
||||
|
||||
DnsResolverJSON []byte
|
||||
|
||||
ApiNodeAddrsJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeSystem_LogUpdateNodeSystemSettings, params.NodeId)
|
||||
|
||||
if params.MaxCPU < 0 {
|
||||
this.Fail("CPU线程数不能小于0")
|
||||
}
|
||||
|
||||
// 系统设置
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeSystem(this.AdminContext(), &pb.UpdateNodeSystemRequest{
|
||||
NodeId: params.NodeId,
|
||||
MaxCPU: params.MaxCPU,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// DNS解析设置
|
||||
var dnsResolverConfig = nodeconfigs.DefaultDNSResolverConfig()
|
||||
err = json.Unmarshal(params.DnsResolverJSON, dnsResolverConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = dnsResolverConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验DNS解析配置失败:" + err.Error())
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeRPC().UpdateNodeDNSResolver(this.AdminContext(), &pb.UpdateNodeDNSResolverRequest{
|
||||
NodeId: params.NodeId,
|
||||
DnsResolverJSON: params.DnsResolverJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// API节点设置
|
||||
var apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
if len(params.ApiNodeAddrsJSON) > 0 {
|
||||
err = json.Unmarshal(params.ApiNodeAddrsJSON, &apiNodeAddrs)
|
||||
if err != nil {
|
||||
this.Fail("API节点地址校验错误:" + err.Error())
|
||||
}
|
||||
for _, addr := range apiNodeAddrs {
|
||||
err = addr.Init()
|
||||
if err != nil {
|
||||
this.Fail("API节点地址校验错误:" + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = this.RPC().NodeRPC().UpdateNodeAPIConfig(this.AdminContext(), &pb.UpdateNodeAPIConfigRequest{
|
||||
NodeId: params.NodeId,
|
||||
ApiNodeAddrsJSON: params.ApiNodeAddrsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package thresholds2
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("threshold")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
// 列出所有阈值
|
||||
thresholdsResp, err := this.RPC().NodeThresholdRPC().FindAllEnabledNodeThresholds(this.AdminContext(), &pb.FindAllEnabledNodeThresholdsRequest{
|
||||
Role: "node",
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
thresholdMaps := []maps.Map{}
|
||||
for _, threshold := range thresholdsResp.NodeThresholds {
|
||||
thresholdMaps = append(thresholdMaps, maps.Map{
|
||||
"id": threshold.Id,
|
||||
"itemName": nodeconfigs.FindNodeValueItemName(threshold.Item),
|
||||
"paramName": nodeconfigs.FindNodeValueItemParamName(threshold.Item, threshold.Param),
|
||||
"paramIsPercent": nodeconfigs.CheckNodeValueItemParamIsPercent(threshold.Item, threshold.Param),
|
||||
"operatorName": nodeconfigs.FindNodeValueOperatorName(threshold.Operator),
|
||||
"value": nodeconfigs.UnmarshalNodeValue(threshold.ValueJSON),
|
||||
"sumMethodName": nodeconfigs.FindNodeValueSumMethodName(threshold.SumMethod),
|
||||
"duration": threshold.Duration,
|
||||
"durationUnitName": nodeconfigs.FindNodeValueDurationUnitName(threshold.DurationUnit),
|
||||
"isOn": threshold.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["thresholds"] = thresholdMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type StartAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StartAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeRPC().StartNode(this.AdminContext(), &pb.StartNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogStartNodeRemotely, params.NodeId)
|
||||
|
||||
if resp.IsOk {
|
||||
this.Success()
|
||||
}
|
||||
|
||||
this.Fail("启动失败:" + resp.Error)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// StatusAction 节点状态
|
||||
type StatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
// 节点
|
||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.Node
|
||||
if node == nil {
|
||||
this.WriteString("找不到要操作的节点")
|
||||
return
|
||||
}
|
||||
|
||||
// 安装信息
|
||||
if node.InstallStatus != nil {
|
||||
this.Data["installStatus"] = maps.Map{
|
||||
"isRunning": node.InstallStatus.IsRunning,
|
||||
"isFinished": node.InstallStatus.IsFinished,
|
||||
"isOk": node.InstallStatus.IsOk,
|
||||
"updatedAt": node.InstallStatus.UpdatedAt,
|
||||
"error": node.InstallStatus.Error,
|
||||
"errorCode": node.InstallStatus.ErrorCode,
|
||||
}
|
||||
} else {
|
||||
this.Data["installStatus"] = nil
|
||||
}
|
||||
|
||||
this.Data["isInstalled"] = node.IsInstalled
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type StopAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StopAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeRPC().StopNode(this.AdminContext(), &pb.StopNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogStopNodeRemotely, params.NodeId)
|
||||
|
||||
if resp.IsOk {
|
||||
this.Success()
|
||||
}
|
||||
|
||||
this.Fail("执行失败:" + resp.Error)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type SyncDomainAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SyncDomainAction) RunPost(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
// 记录日志
|
||||
defer this.CreateLogInfo(codes.DNS_LogSyncDomain, params.DomainId)
|
||||
|
||||
// 执行同步
|
||||
resp, err := this.RPC().DNSDomainRPC().SyncDNSDomainData(this.AdminContext(), &pb.SyncDNSDomainDataRequest{DnsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.IsOk {
|
||||
this.Success()
|
||||
} else {
|
||||
this.Data["shouldFix"] = resp.ShouldFix
|
||||
this.Fail(resp.Error)
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type UninstallAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UninstallAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeRPC().UninstallNode(this.AdminContext(), &pb.UninstallNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogUninstallNodeRemotely, params.NodeId)
|
||||
|
||||
if resp.IsOk {
|
||||
this.Success()
|
||||
}
|
||||
|
||||
this.Fail("执行失败:" + resp.Error)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
// 手动上线
|
||||
type UpAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.Node_LogUpNode, params.NodeId)
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeUp(this.AdminContext(), &pb.UpdateNodeUpRequest{
|
||||
NodeId: params.NodeId,
|
||||
IsUp: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net"
|
||||
)
|
||||
|
||||
type UpdateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateAction) Init() {
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("basic")
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var node = nodeResp.Node
|
||||
if node == nil {
|
||||
this.WriteString("找不到要操作的节点")
|
||||
return
|
||||
}
|
||||
|
||||
var clusterMap maps.Map = nil
|
||||
if node.NodeCluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
"name": node.NodeCluster.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// IP地址
|
||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var ipAddressMaps = []maps.Map{}
|
||||
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
||||
// 阈值
|
||||
thresholds, err := ipaddressutils.InitNodeIPAddressThresholds(this.Parent(), addr.Id)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 专属集群
|
||||
var clusterMaps = []maps.Map{}
|
||||
for _, addrCluster := range addr.NodeClusters {
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": addrCluster.Id,
|
||||
"name": addrCluster.Name,
|
||||
})
|
||||
}
|
||||
|
||||
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
||||
"id": addr.Id,
|
||||
"name": addr.Name,
|
||||
"ip": addr.Ip,
|
||||
"canAccess": addr.CanAccess,
|
||||
"isOn": addr.IsOn,
|
||||
"isUp": addr.IsUp,
|
||||
"thresholds": thresholds,
|
||||
"clusters": clusterMaps,
|
||||
})
|
||||
}
|
||||
|
||||
// 分组
|
||||
var groupMap maps.Map = nil
|
||||
if node.NodeGroup != nil {
|
||||
groupMap = maps.Map{
|
||||
"id": node.NodeGroup.Id,
|
||||
"name": node.NodeGroup.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// 区域
|
||||
var regionMap maps.Map = nil
|
||||
if node.NodeRegion != nil {
|
||||
regionMap = maps.Map{
|
||||
"id": node.NodeRegion.Id,
|
||||
"name": node.NodeRegion.Name,
|
||||
}
|
||||
}
|
||||
|
||||
var nodeMap = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddresses": ipAddressMaps,
|
||||
"cluster": clusterMap,
|
||||
"isOn": node.IsOn,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"level": node.Level,
|
||||
"enableIPLists": node.EnableIPLists,
|
||||
}
|
||||
|
||||
if node.LnAddrs == nil {
|
||||
nodeMap["lnAddrs"] = []string{}
|
||||
} else {
|
||||
nodeMap["lnAddrs"] = node.LnAddrs
|
||||
}
|
||||
|
||||
if node.NodeCluster != nil {
|
||||
nodeMap["primaryCluster"] = maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
"name": node.NodeCluster.Name,
|
||||
}
|
||||
} else {
|
||||
nodeMap["primaryCluster"] = nil
|
||||
}
|
||||
|
||||
if len(node.SecondaryNodeClusters) > 0 {
|
||||
var secondaryClusterMaps = []maps.Map{}
|
||||
for _, cluster := range node.SecondaryNodeClusters {
|
||||
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
nodeMap["secondaryClusters"] = secondaryClusterMaps
|
||||
} else {
|
||||
nodeMap["secondaryClusters"] = []interface{}{}
|
||||
}
|
||||
|
||||
this.Data["node"] = nodeMap
|
||||
|
||||
this.Data["canUpdateLevel"] = this.CanUpdateLevel(2)
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
LoginId int64
|
||||
NodeId int64
|
||||
GroupId int64
|
||||
RegionId int64
|
||||
Name string
|
||||
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
||||
PrimaryClusterId int64
|
||||
SecondaryClusterIds []byte
|
||||
IsOn bool
|
||||
Level int32
|
||||
LnAddrs []string
|
||||
EnableIPLists bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogUpdateNode, params.NodeId)
|
||||
|
||||
if params.NodeId <= 0 {
|
||||
this.Fail("要操作的节点不存在")
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入节点名称")
|
||||
|
||||
// TODO 检查cluster
|
||||
if params.PrimaryClusterId <= 0 {
|
||||
this.Fail("请选择节点所在主集群")
|
||||
}
|
||||
|
||||
var secondaryClusterIds = []int64{}
|
||||
if len(params.SecondaryClusterIds) > 0 {
|
||||
err := json.Unmarshal(params.SecondaryClusterIds, &secondaryClusterIds)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// IP地址
|
||||
var ipAddresses = []maps.Map{}
|
||||
if len(params.IPAddressesJSON) > 0 {
|
||||
err := json.Unmarshal(params.IPAddressesJSON, &ipAddresses)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(ipAddresses) == 0 {
|
||||
this.Fail("请至少输入一个IP地址")
|
||||
}
|
||||
|
||||
// 保存
|
||||
if !this.CanUpdateLevel(params.Level) {
|
||||
this.Fail("没有权限修改节点级别:" + types.String(params.Level))
|
||||
}
|
||||
|
||||
// 检查Ln节点地址
|
||||
var lnAddrs = []string{}
|
||||
if params.Level > 1 {
|
||||
for _, lnAddr := range params.LnAddrs {
|
||||
if len(lnAddr) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 处理 host:port
|
||||
host, _, err := net.SplitHostPort(lnAddr)
|
||||
if err == nil {
|
||||
lnAddr = host
|
||||
}
|
||||
|
||||
if net.ParseIP(lnAddr) == nil {
|
||||
this.Fail("L2级别访问地址 '" + lnAddr + "' 格式错误,请纠正后再提交")
|
||||
}
|
||||
lnAddrs = append(lnAddrs, lnAddr)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
Name: params.Name,
|
||||
NodeClusterId: params.PrimaryClusterId,
|
||||
SecondaryNodeClusterIds: secondaryClusterIds,
|
||||
IsOn: params.IsOn,
|
||||
Level: params.Level,
|
||||
LnAddrs: lnAddrs,
|
||||
EnableIPLists: params.EnableIPLists,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 禁用老的IP地址
|
||||
_, err = this.RPC().NodeIPAddressRPC().DisableAllNodeIPAddressesWithNodeId(this.AdminContext(), &pb.DisableAllNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 添加新的IP地址
|
||||
err = ipaddressutils.UpdateNodeIPAddresses(this.Parent(), params.NodeId, nodeconfigs.NodeRoleNode, params.IPAddressesJSON)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
)
|
||||
|
||||
type UpdateDNSPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateDNSPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdateDNSPopupAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
dnsInfo := dnsInfoResp.Node
|
||||
if dnsInfo == nil {
|
||||
this.NotFound("node", params.NodeId)
|
||||
return
|
||||
}
|
||||
this.Data["ipAddr"] = dnsInfo.IpAddr
|
||||
this.Data["routes"] = domainutils.ConvertRoutesToMaps(dnsInfo)
|
||||
this.Data["domainId"] = dnsInfo.DnsDomainId
|
||||
this.Data["domainName"] = dnsInfo.DnsDomainName
|
||||
|
||||
// 读取所有线路
|
||||
allRouteMaps := []maps.Map{}
|
||||
if dnsInfo.DnsDomainId > 0 {
|
||||
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: dnsInfo.DnsDomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(routesResp.Routes) > 0 {
|
||||
for _, route := range routesResp.Routes {
|
||||
allRouteMaps = append(allRouteMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"domainName": dnsInfo.DnsDomainName,
|
||||
"domainId": dnsInfo.DnsDomainId,
|
||||
})
|
||||
}
|
||||
|
||||
// 筛选
|
||||
var routes = domainutils.FilterRoutes(dnsInfo.Routes, routesResp.Routes)
|
||||
dnsInfo.Routes = routes
|
||||
this.Data["routes"] = domainutils.ConvertRoutesToMaps(dnsInfo)
|
||||
}
|
||||
}
|
||||
this.Data["allRoutes"] = allRouteMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateDNSPopupAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
IpAddr string
|
||||
DomainId int64
|
||||
DnsRoutesJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
// 操作日志
|
||||
defer this.CreateLogInfo(codes.NodeDNS_LogUpdateNodeDNS, params.NodeId)
|
||||
|
||||
routes := []string{}
|
||||
if len(params.DnsRoutesJSON) > 0 {
|
||||
err := json.Unmarshal(params.DnsRoutesJSON, &routes)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("ipAddr", params.IpAddr).
|
||||
Require("请输入IP地址")
|
||||
|
||||
if net.ParseIP(params.IpAddr) == nil {
|
||||
this.FailField("ipAddr", "请输入正确的IP地址")
|
||||
}
|
||||
|
||||
// 执行修改
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeDNS(this.AdminContext(), &pb.UpdateNodeDNSRequest{
|
||||
NodeId: params.NodeId,
|
||||
IpAddr: params.IpAddr,
|
||||
DnsDomainId: params.DomainId,
|
||||
Routes: routes,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type UpdateInstallStatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateInstallStatusAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
IsInstalled bool
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogUpdateNodeInstallationStatus, params.NodeId)
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeIsInstalled(this.AdminContext(), &pb.UpdateNodeIsInstalledRequest{
|
||||
NodeId: params.NodeId,
|
||||
IsInstalled: params.IsInstalled,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type UpdateIsOnAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateIsOnAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
IsOn bool
|
||||
}) {
|
||||
if params.IsOn {
|
||||
defer this.CreateLogInfo(codes.Node_LogUpdateNodeOn, params.NodeId)
|
||||
} else {
|
||||
defer this.CreateLogInfo(codes.Node_LogUpdateNodeOff, params.NodeId)
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeIsOn(this.AdminContext(), &pb.UpdateNodeIsOnRequest{
|
||||
NodeId: params.NodeId,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build !plus
|
||||
|
||||
package node
|
||||
|
||||
func (this *UpdateAction) CanUpdateLevel(level int32) bool {
|
||||
return level <= 1
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package node
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/plus"
|
||||
)
|
||||
|
||||
func (this *UpdateAction) CanUpdateLevel(level int32) bool {
|
||||
return (teaconst.IsPlus && plus.AllowComponent(plus.ComponentCodeL2Node)) || level <= 1
|
||||
}
|
||||
335
EdgeAdmin/internal/web/actions/default/clusters/cluster/nodes.go
Normal file
335
EdgeAdmin/internal/web/actions/default/clusters/cluster/nodes.go
Normal file
@@ -0,0 +1,335 @@
|
||||
package cluster
|
||||
|
||||
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/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NodesAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *NodesAction) Init() {
|
||||
this.Nav("", "node", "index")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *NodesAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
GroupId int64
|
||||
RegionId int64
|
||||
InstalledState int
|
||||
ActiveState int
|
||||
Keyword string
|
||||
Level int32
|
||||
|
||||
CpuOrder string
|
||||
MemoryOrder string
|
||||
TrafficInOrder string
|
||||
TrafficOutOrder string
|
||||
LoadOrder string
|
||||
ConnectionsOrder string
|
||||
}) {
|
||||
this.Data["groupId"] = params.GroupId
|
||||
this.Data["regionId"] = params.RegionId
|
||||
this.Data["installState"] = params.InstalledState
|
||||
this.Data["activeState"] = params.ActiveState
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["level"] = params.Level
|
||||
this.Data["hasOrder"] = len(params.CpuOrder) > 0 || len(params.MemoryOrder) > 0 || len(params.TrafficInOrder) > 0 || len(params.TrafficOutOrder) > 0 || len(params.LoadOrder) > 0 || len(params.ConnectionsOrder) > 0
|
||||
|
||||
// 集群是否已经设置了线路
|
||||
clusterDNSResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["hasClusterDNS"] = clusterDNSResp.Domain != nil
|
||||
|
||||
// 数量
|
||||
countAllResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["countAll"] = countAllResp.Count
|
||||
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
Level: params.Level,
|
||||
InstallState: types.Int32(params.InstalledState),
|
||||
ActiveState: types.Int32(params.ActiveState),
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var page = this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
var req = &pb.ListEnabledNodesMatchRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
Level: params.Level,
|
||||
InstallState: types.Int32(params.InstalledState),
|
||||
ActiveState: types.Int32(params.ActiveState),
|
||||
Keyword: params.Keyword,
|
||||
}
|
||||
if params.CpuOrder == "asc" {
|
||||
req.CpuAsc = true
|
||||
} else if params.CpuOrder == "desc" {
|
||||
req.CpuDesc = true
|
||||
} else if params.MemoryOrder == "asc" {
|
||||
req.MemoryAsc = true
|
||||
} else if params.MemoryOrder == "desc" {
|
||||
req.MemoryDesc = true
|
||||
} else if params.TrafficInOrder == "asc" {
|
||||
req.TrafficInAsc = true
|
||||
} else if params.TrafficInOrder == "desc" {
|
||||
req.TrafficInDesc = true
|
||||
} else if params.TrafficOutOrder == "asc" {
|
||||
req.TrafficOutAsc = true
|
||||
} else if params.TrafficOutOrder == "desc" {
|
||||
req.TrafficOutDesc = true
|
||||
} else if params.LoadOrder == "asc" {
|
||||
req.LoadAsc = true
|
||||
} else if params.LoadOrder == "desc" {
|
||||
req.LoadDesc = true
|
||||
} else if params.ConnectionsOrder == "asc" {
|
||||
req.ConnectionsAsc = true
|
||||
} else if params.ConnectionsOrder == "desc" {
|
||||
req.ConnectionsDesc = true
|
||||
}
|
||||
nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), req)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var nodeMaps = []maps.Map{}
|
||||
for _, node := range nodesResp.Nodes {
|
||||
// 状态
|
||||
var isSynced = false
|
||||
var status = &nodeconfigs.NodeStatus{}
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
continue
|
||||
}
|
||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||
isSynced = status.ConfigVersion == node.Version
|
||||
}
|
||||
|
||||
// IP
|
||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: node.Id,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var ipAddresses = []maps.Map{}
|
||||
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
||||
// 专属集群
|
||||
var addrClusterMaps = []maps.Map{}
|
||||
for _, addrCluster := range addr.NodeClusters {
|
||||
addrClusterMaps = append(addrClusterMaps, maps.Map{
|
||||
"id": addrCluster.Id,
|
||||
"name": addrCluster.Name,
|
||||
})
|
||||
}
|
||||
|
||||
ipAddresses = append(ipAddresses, maps.Map{
|
||||
"id": addr.Id,
|
||||
"name": addr.Name,
|
||||
"ip": addr.Ip,
|
||||
"canAccess": addr.CanAccess,
|
||||
"isUp": addr.IsUp,
|
||||
"isOn": addr.IsOn,
|
||||
"clusters": addrClusterMaps,
|
||||
})
|
||||
}
|
||||
|
||||
// 分组
|
||||
var groupMap maps.Map = nil
|
||||
if node.NodeGroup != nil {
|
||||
groupMap = maps.Map{
|
||||
"id": node.NodeGroup.Id,
|
||||
"name": node.NodeGroup.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// 区域
|
||||
var regionMap maps.Map = nil
|
||||
if node.NodeRegion != nil {
|
||||
regionMap = maps.Map{
|
||||
"id": node.NodeRegion.Id,
|
||||
"name": node.NodeRegion.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// DNS
|
||||
dnsRouteNames := []string{}
|
||||
for _, route := range node.DnsRoutes {
|
||||
dnsRouteNames = append(dnsRouteNames, route.Name)
|
||||
}
|
||||
|
||||
// 从集群
|
||||
var secondaryClusterMaps []maps.Map
|
||||
for _, secondaryCluster := range node.SecondaryNodeClusters {
|
||||
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||
"id": secondaryCluster.Id,
|
||||
"name": secondaryCluster.Name,
|
||||
"isOn": secondaryCluster.IsOn,
|
||||
})
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"isInstalled": node.IsInstalled,
|
||||
"isOn": node.IsOn,
|
||||
"isUp": node.IsUp,
|
||||
"isBackup": node.IsBackupForCluster || node.IsBackupForGroup,
|
||||
"offlineDay": node.OfflineDay,
|
||||
"installStatus": maps.Map{
|
||||
"isRunning": node.InstallStatus.IsRunning,
|
||||
"isFinished": node.InstallStatus.IsFinished,
|
||||
"isOk": node.InstallStatus.IsOk,
|
||||
"error": node.InstallStatus.Error,
|
||||
},
|
||||
"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),
|
||||
"trafficInBytes": status.TrafficInBytes,
|
||||
"trafficOutBytes": status.TrafficOutBytes,
|
||||
"load1m": numberutils.PadFloatZero(numberutils.FormatFloat2(status.Load1m), 2),
|
||||
"countConnections": status.ConnectionCount,
|
||||
},
|
||||
"cluster": maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
"name": node.NodeCluster.Name,
|
||||
},
|
||||
"secondaryClusters": secondaryClusterMaps,
|
||||
"isSynced": isSynced,
|
||||
"ipAddresses": ipAddresses,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"dnsRouteNames": dnsRouteNames,
|
||||
"level": node.Level,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
// 所有分组
|
||||
var groupMaps = []maps.Map{}
|
||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, group := range groupsResp.NodeGroups {
|
||||
countNodesInGroupResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: group.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countNodes := countNodesInGroupResp.Count
|
||||
groupName := group.Name
|
||||
if countNodes > 0 {
|
||||
groupName += "(" + types.String(countNodes) + ")"
|
||||
}
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": groupName,
|
||||
"countNodes": countNodes,
|
||||
})
|
||||
}
|
||||
|
||||
// 是否有未分组
|
||||
if len(groupMaps) > 0 {
|
||||
countNodesInGroupResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: -1,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countUngroupNodes = countNodesInGroupResp.Count
|
||||
if countUngroupNodes > 0 {
|
||||
groupMaps = append([]maps.Map{
|
||||
{
|
||||
"id": -1,
|
||||
"name": "[" + this.Lang(codes.Node_UngroupedLabel) + "](" + types.String(countUngroupNodes) + ")",
|
||||
"countNodes": countUngroupNodes,
|
||||
},
|
||||
}, groupMaps...)
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
// 所有区域
|
||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllAvailableNodeRegions(this.AdminContext(), &pb.FindAllAvailableNodeRegionsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var regionMaps = []maps.Map{}
|
||||
for _, region := range regionsResp.NodeRegions {
|
||||
regionMaps = append(regionMaps, maps.Map{
|
||||
"id": region.Id,
|
||||
"name": region.Name,
|
||||
})
|
||||
}
|
||||
this.Data["regions"] = regionMaps
|
||||
|
||||
// 级别
|
||||
this.Data["levels"] = []maps.Map{}
|
||||
if teaconst.IsPlus {
|
||||
this.Data["levels"] = nodeconfigs.FindAllNodeLevels()
|
||||
}
|
||||
|
||||
// 记录最近访问
|
||||
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
||||
ItemType: "cluster",
|
||||
ItemId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
76
EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/cache/index.go
vendored
Normal file
76
EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/cache/index.go
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("cache")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
cluster, err := dao.SharedNodeClusterDAO.FindEnabledNodeCluster(this.AdminContext(), params.ClusterId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if cluster == nil {
|
||||
this.NotFound("nodeCluster", params.ClusterId)
|
||||
return
|
||||
}
|
||||
|
||||
// 缓存设置
|
||||
this.Data["cachePolicy"] = nil
|
||||
if cluster.HttpCachePolicyId > 0 {
|
||||
cachePolicy, err := dao.SharedHTTPCachePolicyDAO.FindEnabledHTTPCachePolicy(this.AdminContext(), cluster.HttpCachePolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if cachePolicy != nil {
|
||||
this.Data["cachePolicy"] = maps.Map{
|
||||
"id": cachePolicy.Id,
|
||||
"name": cachePolicy.Name,
|
||||
"isOn": cachePolicy.IsOn,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
CachePolicyId int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ServerCache_LogUpdateClusterCachePolicy, params.ClusterId, params.CachePolicyId)
|
||||
|
||||
if params.CachePolicyId <= 0 {
|
||||
this.Fail("请选择缓存策略")
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeClusterRPC().UpdateNodeClusterHTTPCachePolicyId(this.AdminContext(), &pb.UpdateNodeClusterHTTPCachePolicyIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
HttpCachePolicyId: params.CachePolicyId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package cc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("cc")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
httpCCResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterHTTPCCPolicy(this.AdminContext(), &pb.FindEnabledNodeClusterHTTPCCPolicyRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var defaultThresholds = serverconfigs.CloneDefaultHTTPCCThresholds()
|
||||
this.Data["defaultThresholds"] = defaultThresholds
|
||||
|
||||
var thresholds = []*serverconfigs.HTTPCCThreshold{}
|
||||
for range defaultThresholds {
|
||||
thresholds = append(thresholds, serverconfigs.NewHTTPCCThreshold())
|
||||
}
|
||||
this.Data["thresholds"] = thresholds
|
||||
|
||||
if len(httpCCResp.HttpCCPolicyJSON) == 0 {
|
||||
this.Data["httpCCPolicy"] = nodeconfigs.NewHTTPCCPolicy()
|
||||
} else {
|
||||
var config = nodeconfigs.NewHTTPCCPolicy()
|
||||
err = json.Unmarshal(httpCCResp.HttpCCPolicyJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
for index, threshold := range config.Thresholds {
|
||||
if index < len(thresholds) {
|
||||
thresholds[index].Merge(threshold)
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["httpCCPolicy"] = config
|
||||
}
|
||||
|
||||
this.Data["defaultHTTPCCPolicyMaxConnectionsPerIP"] = nodeconfigs.HTTPCCPolicyMaxConnectionsPerIP
|
||||
this.Data["defaultHTTPCCPolicyRedirectsCheckingValidatePath"] = nodeconfigs.HTTPCCPolicyRedirectsCheckingValidatePath
|
||||
this.Data["defaultHTTPCCPolicyRedirectsCheckingDurationSeconds"] = nodeconfigs.HTTPCCPolicyRedirectsCheckingDurationSeconds
|
||||
this.Data["defaultHTTPCCPolicyRedirectsCheckingMaxRedirects"] = nodeconfigs.HTTPCCPolicyRedirectsCheckingMaxRedirects
|
||||
this.Data["defaultHTTPCCPolicyRedirectsCheckingBlockSeconds"] = nodeconfigs.HTTPCCPolicyRedirectsCheckingBlockSeconds
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
IsOn bool
|
||||
|
||||
ThresholdPeriodSeconds []int32
|
||||
ThresholdMaxRequests []int32
|
||||
ThresholdBlockSeconds []int32
|
||||
|
||||
MaxConnectionsPerIP int
|
||||
|
||||
RedirectsCheckingValidatePath string
|
||||
RedirectsCheckingDurationSeconds int
|
||||
RedirectsCheckingMaxRedirects int
|
||||
RedirectsCheckingBlockSeconds int
|
||||
|
||||
FirewallScope string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ServerCC_LogUpdateClusterHTTPCCPolicy, params.ClusterId)
|
||||
|
||||
var config = nodeconfigs.NewHTTPCCPolicy()
|
||||
config.IsOn = params.IsOn
|
||||
|
||||
// 阈值
|
||||
var thresholds = []*serverconfigs.HTTPCCThreshold{}
|
||||
var countThresholdPeriodSeconds = len(params.ThresholdPeriodSeconds)
|
||||
if countThresholdPeriodSeconds == len(params.ThresholdMaxRequests) && countThresholdPeriodSeconds == len(params.ThresholdBlockSeconds) {
|
||||
for index, periodSeconds := range params.ThresholdPeriodSeconds {
|
||||
var maxRequests = params.ThresholdMaxRequests[index]
|
||||
var blockSeconds = params.ThresholdBlockSeconds[index]
|
||||
|
||||
var threshold = serverconfigs.NewHTTPCCThreshold()
|
||||
if periodSeconds >= 0 {
|
||||
threshold.PeriodSeconds = periodSeconds
|
||||
}
|
||||
if maxRequests >= 0 {
|
||||
threshold.MaxRequests = maxRequests
|
||||
}
|
||||
if blockSeconds >= 0 {
|
||||
threshold.BlockSeconds = blockSeconds
|
||||
}
|
||||
thresholds = append(thresholds, threshold)
|
||||
}
|
||||
}
|
||||
config.Thresholds = thresholds
|
||||
|
||||
// 连接数
|
||||
if params.MaxConnectionsPerIP > 0 {
|
||||
config.MaxConnectionsPerIP = params.MaxConnectionsPerIP
|
||||
} else {
|
||||
config.MaxConnectionsPerIP = 0
|
||||
}
|
||||
|
||||
// 跳转
|
||||
if len(params.RedirectsCheckingValidatePath) > 0 && !regexp.MustCompile(`^/[/.\w-]+$`).MatchString(params.RedirectsCheckingValidatePath) {
|
||||
this.FailField("redirectsCheckingValidatePath", "跳转检测路径必须是一个常规URL")
|
||||
return
|
||||
}
|
||||
config.RedirectsChecking.ValidatePath = params.RedirectsCheckingValidatePath
|
||||
if params.RedirectsCheckingDurationSeconds > 0 {
|
||||
config.RedirectsChecking.DurationSeconds = params.RedirectsCheckingDurationSeconds
|
||||
} else {
|
||||
config.RedirectsChecking.DurationSeconds = 0
|
||||
}
|
||||
if params.RedirectsCheckingMaxRedirects > 0 {
|
||||
config.RedirectsChecking.MaxRedirects = params.RedirectsCheckingMaxRedirects
|
||||
} else {
|
||||
config.RedirectsChecking.MaxRedirects = 0
|
||||
}
|
||||
if params.RedirectsCheckingBlockSeconds > 0 {
|
||||
config.RedirectsChecking.BlockSeconds = params.RedirectsCheckingBlockSeconds
|
||||
} else {
|
||||
config.RedirectsChecking.BlockSeconds = 0
|
||||
}
|
||||
|
||||
// 防火墙
|
||||
config.Firewall.Scope = params.FirewallScope
|
||||
|
||||
err := config.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
configJSON, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterHTTPCCPolicy(this.AdminContext(), &pb.UpdateNodeClusterHTTPCCPolicyRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
HttpCCPolicyJSON: configJSON,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ddosProtection
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("ddosProtection")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
|
||||
protectionResp, err := this.RPC().NodeClusterRPC().FindNodeClusterDDoSProtection(this.AdminContext(), &pb.FindNodeClusterDDoSProtectionRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var ddosProtectionConfig = ddosconfigs.DefaultProtectionConfig()
|
||||
if len(protectionResp.DdosProtectionJSON) > 0 {
|
||||
err = json.Unmarshal(protectionResp.DdosProtectionJSON, ddosProtectionConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["config"] = ddosProtectionConfig
|
||||
this.Data["defaultConfigs"] = nodeconfigs.DefaultConfigs
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
DdosProtectionJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.DDoSProtection_LogUpdateClusterDDoSProtection, params.ClusterId)
|
||||
|
||||
var ddosProtectionConfig = &ddosconfigs.ProtectionConfig{}
|
||||
err := json.Unmarshal(params.DdosProtectionJSON, ddosProtectionConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = ddosProtectionConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
// 校验参数
|
||||
if ddosProtectionConfig.TCP != nil {
|
||||
var tcpConfig = ddosProtectionConfig.TCP
|
||||
if tcpConfig.MaxConnectionsPerIP > 0 && tcpConfig.MaxConnectionsPerIP < nodeconfigs.DefaultTCPMinConnectionsPerIP {
|
||||
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
||||
}
|
||||
|
||||
if tcpConfig.NewConnectionsMinutelyRate > 0 && tcpConfig.NewConnectionsMinutelyRate < nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate {
|
||||
this.FailField("tcpNewConnectionsMinutelyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate))
|
||||
}
|
||||
|
||||
if tcpConfig.NewConnectionsSecondlyRate > 0 && tcpConfig.NewConnectionsSecondlyRate < nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate {
|
||||
this.FailField("tcpNewConnectionsSecondlyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate))
|
||||
}
|
||||
|
||||
// Port
|
||||
for _, portConfig := range tcpConfig.Ports {
|
||||
if portConfig.Port > 65535 {
|
||||
this.Fail("端口号" + types.String(portConfig.Port) + "不能大于65535")
|
||||
}
|
||||
}
|
||||
|
||||
// IP
|
||||
for _, ipConfig := range tcpConfig.AllowIPList {
|
||||
if net.ParseIP(ipConfig.IP) == nil {
|
||||
this.Fail("白名单IP '" + ipConfig.IP + "' 格式错误")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterDDoSProtection(this.AdminContext(), &pb.UpdateNodeClusterDDoSProtectionRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
DdosProtectionJSON: params.DdosProtectionJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ddosProtection
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type StatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StatusAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("ddosProtection")
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeCheckLocalFirewall, &messageconfigs.CheckLocalFirewallMessage{
|
||||
Name: "nftables",
|
||||
}, 10, false)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var resultMaps = []maps.Map{}
|
||||
for _, result := range results {
|
||||
var resultMap = maps.Map{
|
||||
"isOk": result.IsOK,
|
||||
"message": result.Message,
|
||||
"nodeId": result.NodeId,
|
||||
"nodeName": result.NodeName,
|
||||
}
|
||||
|
||||
nodeResp, err := this.RPC().NodeRPC().FindNodeDDoSProtection(this.AdminContext(), &pb.FindNodeDDoSProtectionRequest{NodeId: result.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(nodeResp.DdosProtectionJSON) > 0 {
|
||||
var ddosProtection = ddosconfigs.DefaultProtectionConfig()
|
||||
err = json.Unmarshal(nodeResp.DdosProtectionJSON, ddosProtection)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
resultMap["isPrior"] = !ddosProtection.IsPriorEmpty()
|
||||
}
|
||||
resultMaps = append(resultMaps, resultMap)
|
||||
}
|
||||
|
||||
this.Data["results"] = resultMaps
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "index")
|
||||
this.SecondMenu("dns")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
// 是否有域名可选
|
||||
hasDomainsResp, err := this.RPC().DNSDomainRPC().ExistAvailableDomains(this.AdminContext(), &pb.ExistAvailableDomainsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["hasDomains"] = hasDomainsResp.Exist
|
||||
|
||||
// 当前集群的DNS信息
|
||||
this.Data["domainId"] = 0
|
||||
this.Data["domainName"] = ""
|
||||
this.Data["dnsName"] = ""
|
||||
|
||||
dnsInfoResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["dnsName"] = dnsInfoResp.Name
|
||||
this.Data["nodesAutoSync"] = dnsInfoResp.NodesAutoSync
|
||||
this.Data["serversAutoSync"] = dnsInfoResp.ServersAutoSync
|
||||
|
||||
var domainProviderMap = maps.Map{
|
||||
"id": 0,
|
||||
"name": "",
|
||||
}
|
||||
if dnsInfoResp.Domain != nil {
|
||||
this.Data["domainId"] = dnsInfoResp.Domain.Id
|
||||
this.Data["domainName"] = dnsInfoResp.Domain.Name
|
||||
|
||||
if dnsInfoResp.Provider != nil {
|
||||
domainProviderMap = maps.Map{
|
||||
"id": dnsInfoResp.Provider.Id,
|
||||
"name": dnsInfoResp.Provider.Name,
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["domainProvider"] = domainProviderMap
|
||||
|
||||
if len(dnsInfoResp.CnameRecords) == 0 {
|
||||
this.Data["cnameRecords"] = []string{}
|
||||
} else {
|
||||
this.Data["cnameRecords"] = dnsInfoResp.CnameRecords
|
||||
}
|
||||
this.Data["ttl"] = dnsInfoResp.Ttl
|
||||
this.Data["cnameAsDomain"] = dnsInfoResp.CnameAsDomain
|
||||
this.Data["includingLnNodes"] = dnsInfoResp.IncludingLnNodes
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
|
||||
DnsDomainId int64
|
||||
DnsName string
|
||||
NodesAutoSync bool
|
||||
ServersAutoSync bool
|
||||
CnameRecords []string
|
||||
Ttl int32
|
||||
CnameAsDomain bool
|
||||
IncludingLnNodes bool
|
||||
|
||||
ConfirmResetDomain bool // 是否确认重置域名
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.DNS_LogUpdateClusterDNS, params.ClusterId)
|
||||
|
||||
if !params.ConfirmResetDomain {
|
||||
if params.DnsDomainId <= 0 {
|
||||
this.Fail("请选择集群的主域名")
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("dnsName", params.DnsName).
|
||||
Require("请输入DNS子域名")
|
||||
}
|
||||
|
||||
// 检查DNS名称
|
||||
if len(params.DnsName) > 0 {
|
||||
if !domainutils.ValidateDomainFormat(params.DnsName) {
|
||||
this.FailField("dnsName", "请输入正确的DNS子域名")
|
||||
}
|
||||
|
||||
// 检查是否已经被使用
|
||||
resp, err := this.RPC().NodeClusterRPC().CheckNodeClusterDNSName(this.AdminContext(), &pb.CheckNodeClusterDNSNameRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
DnsName: params.DnsName,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.IsUsed {
|
||||
this.FailField("dnsName", "此DNS子域名已经被使用,请换一个再试")
|
||||
}
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeClusterRPC().UpdateNodeClusterDNS(this.AdminContext(), &pb.UpdateNodeClusterDNSRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
DnsName: params.DnsName,
|
||||
DnsDomainId: params.DnsDomainId,
|
||||
NodesAutoSync: params.NodesAutoSync,
|
||||
ServersAutoSync: params.ServersAutoSync,
|
||||
CnameRecords: params.CnameRecords,
|
||||
Ttl: params.Ttl,
|
||||
CnameAsDomain: params.CnameAsDomain,
|
||||
IncludingLnNodes: params.IncludingLnNodes,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
)
|
||||
|
||||
type RandomNameAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *RandomNameAction) RunPost(params struct{}) {
|
||||
this.Data["name"] = "cluster" + rands.HexString(8)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iputils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type RecordsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *RecordsAction) Init() {
|
||||
this.Nav("", "setting", "records")
|
||||
this.SecondMenu("dns")
|
||||
}
|
||||
|
||||
func (this *RecordsAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
// 集群信息
|
||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var cluster = clusterResp.NodeCluster
|
||||
if cluster == nil {
|
||||
this.NotFound("nodeCluster", params.ClusterId)
|
||||
return
|
||||
}
|
||||
this.Data["cluster"] = maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
}
|
||||
|
||||
// DNS信息
|
||||
dnsResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var defaultRoute = dnsResp.DefaultRoute
|
||||
var domainName = ""
|
||||
var dnsMap = maps.Map{
|
||||
"dnsName": dnsResp.Name,
|
||||
"domainId": 0,
|
||||
"domainName": "",
|
||||
"providerId": 0,
|
||||
"providerName": "",
|
||||
"providerTypeName": "",
|
||||
}
|
||||
if dnsResp.Domain != nil {
|
||||
domainName = dnsResp.Domain.Name
|
||||
dnsMap["domainId"] = dnsResp.Domain.Id
|
||||
dnsMap["domainName"] = dnsResp.Domain.Name
|
||||
}
|
||||
if dnsResp.Provider != nil {
|
||||
dnsMap["providerId"] = dnsResp.Provider.Id
|
||||
dnsMap["providerName"] = dnsResp.Provider.Name
|
||||
dnsMap["providerTypeName"] = dnsResp.Provider.TypeName
|
||||
}
|
||||
|
||||
if len(dnsResp.CnameRecords) > 0 {
|
||||
dnsMap["cnameRecords"] = dnsResp.CnameRecords
|
||||
} else {
|
||||
dnsMap["cnameRecords"] = []string{}
|
||||
}
|
||||
|
||||
this.Data["dnsInfo"] = dnsMap
|
||||
|
||||
// 未安装的节点
|
||||
notInstalledNodesResp, err := this.RPC().NodeRPC().FindAllEnabledNodesDNSWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodesDNSWithNodeClusterIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
IsInstalled: false,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var allNodes = notInstalledNodesResp.Nodes
|
||||
|
||||
// 节点DNS解析记录
|
||||
nodesResp, err := this.RPC().NodeRPC().FindAllEnabledNodesDNSWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodesDNSWithNodeClusterIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
IsInstalled: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var installedNodeIdsMap = map[int64]bool{}
|
||||
for _, node := range nodesResp.Nodes {
|
||||
installedNodeIdsMap[node.Id] = true
|
||||
}
|
||||
|
||||
allNodes = append(allNodes, nodesResp.Nodes...)
|
||||
|
||||
var nodeMaps = []maps.Map{}
|
||||
for _, node := range allNodes {
|
||||
var isInstalled = installedNodeIdsMap[node.Id]
|
||||
|
||||
if len(node.Routes) > 0 {
|
||||
for _, route := range node.Routes {
|
||||
// 检查是否已解析
|
||||
var isResolved = false
|
||||
if isInstalled && cluster.DnsDomainId > 0 && len(cluster.DnsName) > 0 && len(node.IpAddr) > 0 {
|
||||
var recordType = "A"
|
||||
if iputils.IsIPv6(node.IpAddr) {
|
||||
recordType = "AAAA"
|
||||
}
|
||||
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
||||
DnsDomainId: cluster.DnsDomainId,
|
||||
Name: cluster.DnsName,
|
||||
Type: recordType,
|
||||
Route: route.Code,
|
||||
Value: node.IpAddr,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
isResolved = checkResp.IsOk
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddr": node.IpAddr,
|
||||
"ipAddrId": node.NodeIPAddressId,
|
||||
"route": maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
},
|
||||
"clusterId": node.NodeClusterId,
|
||||
"isResolved": isResolved,
|
||||
"isInstalled": isInstalled,
|
||||
"isBackup": node.IsBackupForCluster || node.IsBackupForGroup,
|
||||
"isOffline": node.IsOffline,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// 默认线路
|
||||
var isResolved = false
|
||||
if isInstalled && len(defaultRoute) > 0 {
|
||||
var recordType = "A"
|
||||
if iputils.IsIPv6(node.IpAddr) {
|
||||
recordType = "AAAA"
|
||||
}
|
||||
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
||||
DnsDomainId: cluster.DnsDomainId,
|
||||
Name: cluster.DnsName,
|
||||
Type: recordType,
|
||||
Route: defaultRoute,
|
||||
Value: node.IpAddr,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
isResolved = checkResp.IsOk
|
||||
}
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddr": node.IpAddr,
|
||||
"ipAddrId": node.NodeIPAddressId,
|
||||
"route": maps.Map{
|
||||
"name": "",
|
||||
"code": "",
|
||||
},
|
||||
"clusterId": node.NodeClusterId,
|
||||
"isResolved": isResolved,
|
||||
"isInstalled": isInstalled,
|
||||
"isBackup": node.IsBackupForCluster || node.IsBackupForGroup,
|
||||
"isOffline": node.IsOffline,
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
// 代理服务解析记录
|
||||
serversResp, err := this.RPC().ServerRPC().FindAllEnabledServersDNSWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledServersDNSWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var serverMaps = []maps.Map{}
|
||||
for _, server := range serversResp.Servers {
|
||||
// 检查是否已解析
|
||||
isResolved := false
|
||||
if cluster.DnsDomainId > 0 && len(cluster.DnsName) > 0 && len(server.DnsName) > 0 && len(domainName) > 0 {
|
||||
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
||||
DnsDomainId: cluster.DnsDomainId,
|
||||
Name: server.DnsName,
|
||||
Type: "CNAME",
|
||||
Value: cluster.DnsName + "." + domainName,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
isResolved = checkResp.IsOk
|
||||
}
|
||||
|
||||
serverMaps = append(serverMaps, maps.Map{
|
||||
"id": server.Id,
|
||||
"name": server.Name,
|
||||
"dnsName": server.DnsName,
|
||||
"isResolved": isResolved,
|
||||
})
|
||||
}
|
||||
this.Data["servers"] = serverMaps
|
||||
|
||||
// 检查解析记录是否有变化
|
||||
checkChangesResp, err := this.RPC().NodeClusterRPC().CheckNodeClusterDNSChanges(this.AdminContext(), &pb.CheckNodeClusterDNSChangesRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["dnsHasChanges"] = checkChangesResp.IsChanged
|
||||
|
||||
// 需要解决的问题
|
||||
issuesResp, err := this.RPC().DNSRPC().FindAllDNSIssues(this.AdminContext(), &pb.FindAllDNSIssuesRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var issueMaps = []maps.Map{}
|
||||
for _, issue := range issuesResp.Issues {
|
||||
issueMaps = append(issueMaps, maps.Map{
|
||||
"target": issue.Target,
|
||||
"targetId": issue.TargetId,
|
||||
"type": issue.Type,
|
||||
"description": issue.Description,
|
||||
"params": issue.Params,
|
||||
})
|
||||
}
|
||||
this.Data["issues"] = issueMaps
|
||||
|
||||
// 当前正在执行的任务
|
||||
resp, err := this.RPC().DNSTaskRPC().FindAllDoingDNSTasks(this.AdminContext(), &pb.FindAllDoingDNSTasksRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var taskMaps = []maps.Map{}
|
||||
for _, task := range resp.DnsTasks {
|
||||
var clusterMap maps.Map = nil
|
||||
var nodeMap maps.Map = nil
|
||||
var serverMap maps.Map = nil
|
||||
var domainMap maps.Map = nil
|
||||
|
||||
if task.NodeCluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": task.NodeCluster.Id,
|
||||
"name": task.NodeCluster.Name,
|
||||
}
|
||||
}
|
||||
if task.Node != nil {
|
||||
nodeMap = maps.Map{
|
||||
"id": task.Node.Id,
|
||||
"name": task.Node.Name,
|
||||
}
|
||||
}
|
||||
if task.Server != nil {
|
||||
serverMap = maps.Map{
|
||||
"id": task.Server.Id,
|
||||
"name": task.Server.Name,
|
||||
}
|
||||
}
|
||||
if task.DnsDomain != nil {
|
||||
domainMap = maps.Map{
|
||||
"id": task.DnsDomain.Id,
|
||||
"name": task.DnsDomain.Name,
|
||||
}
|
||||
}
|
||||
|
||||
taskMaps = append(taskMaps, maps.Map{
|
||||
"id": task.Id,
|
||||
"type": task.Type,
|
||||
"isDone": task.IsDone,
|
||||
"isOk": task.IsOk,
|
||||
"error": task.Error,
|
||||
"updatedTime": timeutil.FormatTime("Y-m-d H:i:s", task.UpdatedAt),
|
||||
"cluster": clusterMap,
|
||||
"node": nodeMap,
|
||||
"server": serverMap,
|
||||
"domain": domainMap,
|
||||
})
|
||||
}
|
||||
this.Data["tasks"] = taskMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package firewallActions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["actionTypes"] = firewallconfigs.FindAllFirewallActionTypes()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Name string
|
||||
EventLevel string
|
||||
Type string
|
||||
|
||||
// ipset
|
||||
IpsetWhiteName string
|
||||
IpsetBlackName string
|
||||
IpsetWhiteNameIPv6 string
|
||||
IpsetBlackNameIPv6 string
|
||||
IpsetAutoAddToIPTables bool
|
||||
IpsetAutoAddToFirewalld bool
|
||||
|
||||
// script
|
||||
ScriptPath string
|
||||
|
||||
// http api
|
||||
HttpAPIURL string
|
||||
|
||||
// html
|
||||
HtmlContent string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.WAFAction_LogCreateWAFAction, params.ClusterId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入动作名称").
|
||||
Field("type", params.Type).
|
||||
Require("请选择动作类型")
|
||||
|
||||
var actionParams interface{} = nil
|
||||
switch params.Type {
|
||||
case firewallconfigs.FirewallActionTypeIPSet:
|
||||
params.Must.
|
||||
Field("ipsetWhiteName", params.IpsetWhiteName).
|
||||
Require("请输入IPSet白名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet白名单名称").
|
||||
Field("ipsetBlackName", params.IpsetBlackName).
|
||||
Require("请输入IPSet黑名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet黑名单名称").
|
||||
Field("ipsetWhiteNameIPv6", params.IpsetWhiteNameIPv6).
|
||||
Require("请输入IPSet IPv6白名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet IPv6白名单名称").
|
||||
Field("ipsetBlackNameIPv6", params.IpsetBlackNameIPv6).
|
||||
Require("请输入IPSet IPv6黑名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet IPv6黑名单名称")
|
||||
|
||||
actionParams = &firewallconfigs.FirewallActionIPSetConfig{
|
||||
WhiteName: params.IpsetWhiteName,
|
||||
BlackName: params.IpsetBlackName,
|
||||
WhiteNameIPv6: params.IpsetWhiteNameIPv6,
|
||||
BlackNameIPv6: params.IpsetBlackNameIPv6,
|
||||
AutoAddToIPTables: params.IpsetAutoAddToIPTables,
|
||||
AutoAddToFirewalld: params.IpsetAutoAddToFirewalld,
|
||||
}
|
||||
case firewallconfigs.FirewallActionTypeIPTables:
|
||||
actionParams = &firewallconfigs.FirewallActionIPTablesConfig{}
|
||||
case firewallconfigs.FirewallActionTypeFirewalld:
|
||||
actionParams = &firewallconfigs.FirewallActionFirewalldConfig{}
|
||||
case firewallconfigs.FirewallActionTypeScript:
|
||||
params.Must.
|
||||
Field("scriptPath", params.ScriptPath).
|
||||
Require("请输入脚本路径")
|
||||
actionParams = &firewallconfigs.FirewallActionScriptConfig{
|
||||
Path: params.ScriptPath,
|
||||
}
|
||||
case firewallconfigs.FirewallActionTypeHTTPAPI:
|
||||
params.Must.
|
||||
Field("httpAPIURL", params.HttpAPIURL).
|
||||
Require("请输入API URL").
|
||||
Match(`^(http|https):`, "API地址必须以http://或https://开头")
|
||||
actionParams = &firewallconfigs.FirewallActionHTTPAPIConfig{
|
||||
URL: params.HttpAPIURL,
|
||||
}
|
||||
case firewallconfigs.FirewallActionTypeHTML:
|
||||
params.Must.
|
||||
Field("htmlContent", params.HtmlContent).
|
||||
Require("请输入HTML内容")
|
||||
actionParams = &firewallconfigs.FirewallActionHTMLConfig{
|
||||
Content: params.HtmlContent,
|
||||
}
|
||||
default:
|
||||
this.Fail("选择的类型'" + params.Type + "'暂时不支持")
|
||||
}
|
||||
|
||||
actionParamsJSON, err := json.Marshal(actionParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterFirewallActionRPC().CreateNodeClusterFirewallAction(this.AdminContext(), &pb.CreateNodeClusterFirewallActionRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
EventLevel: params.EventLevel,
|
||||
Type: params.Type,
|
||||
ParamsJSON: actionParamsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package firewallActions
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
ActionId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.WAFAction_LogDeleteWAFAction, params.ActionId)
|
||||
|
||||
_, err := this.RPC().NodeClusterFirewallActionRPC().DeleteNodeClusterFirewallAction(this.AdminContext(), &pb.DeleteNodeClusterFirewallActionRequest{NodeClusterFirewallActionId: params.ActionId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package firewallActions
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("firewallAction")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
actionsResp, err := this.RPC().NodeClusterFirewallActionRPC().FindAllEnabledNodeClusterFirewallActions(this.AdminContext(), &pb.FindAllEnabledNodeClusterFirewallActionsRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
levelMaps := map[string][]maps.Map{} // level => actionMaps
|
||||
for _, action := range actionsResp.NodeClusterFirewallActions {
|
||||
actionMaps, ok := levelMaps[action.EventLevel]
|
||||
if !ok {
|
||||
actionMaps = []maps.Map{}
|
||||
}
|
||||
|
||||
actionMaps = append(actionMaps, maps.Map{
|
||||
"id": action.Id,
|
||||
"name": action.Name,
|
||||
"type": action.Type,
|
||||
"typeName": firewallconfigs.FindFirewallActionTypeName(action.Type),
|
||||
})
|
||||
levelMaps[action.EventLevel] = actionMaps
|
||||
}
|
||||
|
||||
levelMaps2 := []maps.Map{} // []levelMap
|
||||
hasActions := false
|
||||
for _, level := range firewallconfigs.FindAllFirewallEventLevels() {
|
||||
actionMaps, ok := levelMaps[level.Code]
|
||||
if !ok {
|
||||
actionMaps = []maps.Map{}
|
||||
} else {
|
||||
hasActions = true
|
||||
}
|
||||
|
||||
levelMaps2 = append(levelMaps2, maps.Map{
|
||||
"name": level.Name,
|
||||
"code": level.Code,
|
||||
"actions": actionMaps,
|
||||
})
|
||||
}
|
||||
|
||||
this.Data["levels"] = levelMaps2
|
||||
this.Data["hasActions"] = hasActions
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package firewallActions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
ActionId int64
|
||||
}) {
|
||||
actionResp, err := this.RPC().NodeClusterFirewallActionRPC().FindEnabledNodeClusterFirewallAction(this.AdminContext(), &pb.FindEnabledNodeClusterFirewallActionRequest{NodeClusterFirewallActionId: params.ActionId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
action := actionResp.NodeClusterFirewallAction
|
||||
if action == nil {
|
||||
this.NotFound("nodeClusterFirewallAction", params.ActionId)
|
||||
return
|
||||
}
|
||||
|
||||
actionParams := maps.Map{}
|
||||
if len(action.ParamsJSON) > 0 {
|
||||
err = json.Unmarshal(action.ParamsJSON, &actionParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["action"] = maps.Map{
|
||||
"id": action.Id,
|
||||
"name": action.Name,
|
||||
"eventLevel": action.EventLevel,
|
||||
"params": actionParams,
|
||||
"type": action.Type,
|
||||
}
|
||||
|
||||
// 通用参数
|
||||
this.Data["actionTypes"] = firewallconfigs.FindAllFirewallActionTypes()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
ActionId int64
|
||||
Name string
|
||||
EventLevel string
|
||||
Type string
|
||||
|
||||
// ipset
|
||||
IpsetWhiteName string
|
||||
IpsetBlackName string
|
||||
IpsetWhiteNameIPv6 string
|
||||
IpsetBlackNameIPv6 string
|
||||
IpsetAutoAddToIPTables bool
|
||||
IpsetAutoAddToFirewalld bool
|
||||
|
||||
// script
|
||||
ScriptPath string
|
||||
|
||||
// http api
|
||||
HttpAPIURL string
|
||||
|
||||
// HTML内容
|
||||
HtmlContent string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.WAFAction_LogUpdateWAFAction, params.ActionId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入动作名称").
|
||||
Field("type", params.Type).
|
||||
Require("请选择动作类型")
|
||||
|
||||
var actionParams interface{} = nil
|
||||
switch params.Type {
|
||||
case firewallconfigs.FirewallActionTypeIPSet:
|
||||
params.Must.
|
||||
Field("ipsetWhiteName", params.IpsetWhiteName).
|
||||
Require("请输入IPSet白名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet白名单名称").
|
||||
Field("ipsetBlackName", params.IpsetBlackName).
|
||||
Require("请输入IPSet黑名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet黑名单名称").
|
||||
Field("ipsetWhiteNameIPv6", params.IpsetWhiteNameIPv6).
|
||||
Require("请输入IPSet IPv6白名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet IPv6白名单名称").
|
||||
Field("ipsetBlackNameIPv6", params.IpsetBlackNameIPv6).
|
||||
Require("请输入IPSet IPv6黑名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet IPv6黑名单名称")
|
||||
|
||||
actionParams = &firewallconfigs.FirewallActionIPSetConfig{
|
||||
WhiteName: params.IpsetWhiteName,
|
||||
BlackName: params.IpsetBlackName,
|
||||
WhiteNameIPv6: params.IpsetWhiteNameIPv6,
|
||||
BlackNameIPv6: params.IpsetBlackNameIPv6,
|
||||
AutoAddToIPTables: params.IpsetAutoAddToIPTables,
|
||||
AutoAddToFirewalld: params.IpsetAutoAddToFirewalld,
|
||||
}
|
||||
case firewallconfigs.FirewallActionTypeIPTables:
|
||||
actionParams = &firewallconfigs.FirewallActionIPTablesConfig{}
|
||||
case firewallconfigs.FirewallActionTypeFirewalld:
|
||||
actionParams = &firewallconfigs.FirewallActionFirewalldConfig{}
|
||||
case firewallconfigs.FirewallActionTypeScript:
|
||||
params.Must.
|
||||
Field("scriptPath", params.ScriptPath).
|
||||
Require("请输入脚本路径")
|
||||
actionParams = &firewallconfigs.FirewallActionScriptConfig{
|
||||
Path: params.ScriptPath,
|
||||
}
|
||||
case firewallconfigs.FirewallActionTypeHTTPAPI:
|
||||
params.Must.
|
||||
Field("httpAPIURL", params.HttpAPIURL).
|
||||
Require("请输入API URL").
|
||||
Match(`^(http|https):`, "API地址必须以http://或https://开头")
|
||||
actionParams = &firewallconfigs.FirewallActionHTTPAPIConfig{
|
||||
URL: params.HttpAPIURL,
|
||||
}
|
||||
case firewallconfigs.FirewallActionTypeHTML:
|
||||
params.Must.
|
||||
Field("htmlContent", params.HtmlContent).
|
||||
Require("请输入HTML内容")
|
||||
actionParams = &firewallconfigs.FirewallActionHTMLConfig{
|
||||
Content: params.HtmlContent,
|
||||
}
|
||||
default:
|
||||
this.Fail("选择的类型'" + params.Type + "'暂时不支持")
|
||||
}
|
||||
|
||||
actionParamsJSON, err := json.Marshal(actionParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterFirewallActionRPC().UpdateNodeClusterFirewallAction(this.AdminContext(), &pb.UpdateNodeClusterFirewallActionRequest{
|
||||
NodeClusterFirewallActionId: params.ActionId,
|
||||
Name: params.Name,
|
||||
EventLevel: params.EventLevel,
|
||||
Type: params.Type,
|
||||
ParamsJSON: actionParamsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package globalServerConfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("globalServerConfig")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
configResp, err := this.RPC().NodeClusterRPC().FindNodeClusterGlobalServerConfig(this.AdminContext(), &pb.FindNodeClusterGlobalServerConfigRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var configJSON = configResp.GlobalServerConfigJSON
|
||||
var config = serverconfigs.NewGlobalServerConfig()
|
||||
if len(configJSON) > 0 {
|
||||
err = json.Unmarshal(configJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["config"] = config
|
||||
|
||||
var httpAllDomainMismatchActionCode = serverconfigs.DomainMismatchActionPage
|
||||
var httpAllDomainMismatchActionContentHTML string
|
||||
var httpAllDomainMismatchActionStatusCode = "404"
|
||||
|
||||
var httpAllDomainMismatchActionRedirectURL = ""
|
||||
|
||||
if config.HTTPAll.DomainMismatchAction != nil {
|
||||
httpAllDomainMismatchActionCode = config.HTTPAll.DomainMismatchAction.Code
|
||||
|
||||
if config.HTTPAll.DomainMismatchAction.Options != nil {
|
||||
// 即使是非 page 处理动作,也读取这些内容,以便于在切换到 page 时,可以顺利读取到先前的设置
|
||||
httpAllDomainMismatchActionContentHTML = config.HTTPAll.DomainMismatchAction.Options.GetString("contentHTML")
|
||||
var statusCode = config.HTTPAll.DomainMismatchAction.Options.GetInt("statusCode")
|
||||
if statusCode > 0 {
|
||||
httpAllDomainMismatchActionStatusCode = types.String(statusCode)
|
||||
}
|
||||
|
||||
if config.HTTPAll.DomainMismatchAction.Code == serverconfigs.DomainMismatchActionRedirect {
|
||||
httpAllDomainMismatchActionRedirectURL = config.HTTPAll.DomainMismatchAction.Options.GetString("url")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
httpAllDomainMismatchActionContentHTML = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>404 not found</title>
|
||||
<style>
|
||||
* { font-family: Roboto, system-ui, sans-serif; }
|
||||
h3, p { text-align: center; }
|
||||
p { color: grey; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h3>Error: 404 Page Not Found</h3>
|
||||
<h3>找不到您要访问的页面。</h3>
|
||||
|
||||
<p>原因:找不到当前访问域名对应的网站,请联系网站管理员。</p>
|
||||
|
||||
</body>
|
||||
</html>`
|
||||
}
|
||||
|
||||
this.Data["httpAllDomainMismatchActionCode"] = httpAllDomainMismatchActionCode
|
||||
this.Data["httpAllDomainMismatchActionContentHTML"] = httpAllDomainMismatchActionContentHTML
|
||||
this.Data["httpAllDomainMismatchActionStatusCode"] = httpAllDomainMismatchActionStatusCode
|
||||
|
||||
this.Data["httpAllDomainMismatchActionRedirectURL"] = httpAllDomainMismatchActionRedirectURL
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
|
||||
HttpAllMatchDomainStrictly bool
|
||||
HttpAllDomainMismatchActionCode string
|
||||
HttpAllDomainMismatchActionContentHTML string
|
||||
HttpAllDomainMismatchActionStatusCode string
|
||||
HttpAllDomainMismatchActionRedirectURL string
|
||||
HttpAllAllowMismatchDomainsJSON []byte
|
||||
HttpAllAllowNodeIP bool
|
||||
HttpAllDefaultDomain string
|
||||
HttpAllNodeIPPageHTML string
|
||||
HttpAllNodeIPShowPage bool
|
||||
HttpAllEnableServerAddrVariable bool
|
||||
HttpAllRequestOriginsWithEncodings bool
|
||||
HttpAllXFFMaxAddresses int
|
||||
|
||||
HttpAllDomainAuditingIsOn bool
|
||||
HttpAllDomainAuditingPrompt string
|
||||
|
||||
HttpAllServerName string
|
||||
HttpAllSupportsLowVersionHTTP bool
|
||||
HttpAllMatchCertFromAllServers bool
|
||||
HttpAllForceLnRequest bool
|
||||
HttpAllLnRequestSchedulingMethod string
|
||||
|
||||
HttpAccessLogIsOn bool
|
||||
HttpAccessLogEnableRequestHeaders bool
|
||||
HttpAccessLogEnableResponseHeaders bool
|
||||
HttpAccessLogCommonRequestHeadersOnly bool
|
||||
HttpAccessLogEnableCookies bool
|
||||
HttpAccessLogEnableServerNotFound bool
|
||||
|
||||
LogRecordServerError bool
|
||||
|
||||
PerformanceAutoReadTimeout bool
|
||||
PerformanceAutoWriteTimeout bool
|
||||
PerformanceDebug bool
|
||||
|
||||
// TCP端口设置
|
||||
TcpAllPortRangeMin int
|
||||
TcpAllPortRangeMax int
|
||||
TcpAllDenyPorts []int
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ServerGlobalSetting_LogUpdateClusterGlobalServerConfig, params.ClusterId)
|
||||
|
||||
configResp, err := this.RPC().NodeClusterRPC().FindNodeClusterGlobalServerConfig(this.AdminContext(), &pb.FindNodeClusterGlobalServerConfigRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var configJSON = configResp.GlobalServerConfigJSON
|
||||
var config = serverconfigs.NewGlobalServerConfig()
|
||||
if len(configJSON) > 0 {
|
||||
err = json.Unmarshal(configJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var domainMisMatchStatusCodeString = params.HttpAllDomainMismatchActionStatusCode
|
||||
if !regexp.MustCompile(`^\d{3}$`).MatchString(domainMisMatchStatusCodeString) {
|
||||
this.FailField("httpAllDomainMismatchActionContentStatusCode", "请输入正确的状态码")
|
||||
return
|
||||
}
|
||||
var domainMisMatchStatusCode = types.Int(domainMisMatchStatusCodeString)
|
||||
|
||||
config.HTTPAll.MatchDomainStrictly = params.HttpAllMatchDomainStrictly
|
||||
|
||||
// validate
|
||||
if config.HTTPAll.MatchDomainStrictly {
|
||||
// validate redirect
|
||||
if params.HttpAllDomainMismatchActionCode == serverconfigs.DomainMismatchActionRedirect {
|
||||
if len(params.HttpAllDomainMismatchActionRedirectURL) == 0 {
|
||||
this.FailField("httpAllDomainMismatchActionRedirectURL", "请输入跳转目标网址URL")
|
||||
return
|
||||
}
|
||||
if !regexp.MustCompile(`(?i)(http|https)://`).MatchString(params.HttpAllDomainMismatchActionRedirectURL) {
|
||||
this.FailField("httpAllDomainMismatchActionRedirectURL", "目标网址URL必须以http://或https://开头")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config.HTTPAll.DomainMismatchAction = &serverconfigs.DomainMismatchAction{
|
||||
Code: params.HttpAllDomainMismatchActionCode,
|
||||
Options: maps.Map{
|
||||
"statusCode": domainMisMatchStatusCode, // page
|
||||
"contentHTML": params.HttpAllDomainMismatchActionContentHTML, // page
|
||||
"url": params.HttpAllDomainMismatchActionRedirectURL, // redirect
|
||||
},
|
||||
}
|
||||
|
||||
var allowMismatchDomains = []string{}
|
||||
if len(params.HttpAllAllowMismatchDomainsJSON) > 0 {
|
||||
err = json.Unmarshal(params.HttpAllAllowMismatchDomainsJSON, &allowMismatchDomains)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 域名
|
||||
config.HTTPAll.AllowMismatchDomains = allowMismatchDomains
|
||||
config.HTTPAll.AllowNodeIP = params.HttpAllAllowNodeIP
|
||||
config.HTTPAll.DefaultDomain = params.HttpAllDefaultDomain
|
||||
config.HTTPAll.NodeIPShowPage = params.HttpAllNodeIPShowPage
|
||||
config.HTTPAll.NodeIPPageHTML = params.HttpAllNodeIPPageHTML
|
||||
|
||||
config.HTTPAll.DomainAuditingIsOn = params.HttpAllDomainAuditingIsOn
|
||||
config.HTTPAll.DomainAuditingPrompt = params.HttpAllDomainAuditingPrompt
|
||||
|
||||
// HTTP All
|
||||
config.HTTPAll.ServerName = params.HttpAllServerName
|
||||
config.HTTPAll.SupportsLowVersionHTTP = params.HttpAllSupportsLowVersionHTTP
|
||||
config.HTTPAll.MatchCertFromAllServers = params.HttpAllMatchCertFromAllServers
|
||||
config.HTTPAll.ForceLnRequest = params.HttpAllForceLnRequest
|
||||
config.HTTPAll.LnRequestSchedulingMethod = params.HttpAllLnRequestSchedulingMethod
|
||||
config.HTTPAll.EnableServerAddrVariable = params.HttpAllEnableServerAddrVariable
|
||||
config.HTTPAll.RequestOriginsWithEncodings = params.HttpAllRequestOriginsWithEncodings
|
||||
config.HTTPAll.XFFMaxAddresses = params.HttpAllXFFMaxAddresses
|
||||
|
||||
// 访问日志
|
||||
config.HTTPAccessLog.IsOn = params.HttpAccessLogIsOn
|
||||
config.HTTPAccessLog.EnableRequestHeaders = params.HttpAccessLogEnableRequestHeaders
|
||||
config.HTTPAccessLog.EnableResponseHeaders = params.HttpAccessLogEnableResponseHeaders
|
||||
config.HTTPAccessLog.CommonRequestHeadersOnly = params.HttpAccessLogCommonRequestHeadersOnly
|
||||
config.HTTPAccessLog.EnableCookies = params.HttpAccessLogEnableCookies
|
||||
config.HTTPAccessLog.EnableServerNotFound = params.HttpAccessLogEnableServerNotFound
|
||||
|
||||
// 日志
|
||||
config.Log.RecordServerError = params.LogRecordServerError
|
||||
|
||||
// TCP
|
||||
if params.TcpAllPortRangeMin < 1024 {
|
||||
params.TcpAllPortRangeMin = 1024
|
||||
}
|
||||
if params.TcpAllPortRangeMax > 65534 {
|
||||
params.TcpAllPortRangeMax = 65534
|
||||
} else if params.TcpAllPortRangeMax < 1024 {
|
||||
params.TcpAllPortRangeMax = 1024
|
||||
}
|
||||
if params.TcpAllPortRangeMin > params.TcpAllPortRangeMax {
|
||||
params.TcpAllPortRangeMin, params.TcpAllPortRangeMax = params.TcpAllPortRangeMax, params.TcpAllPortRangeMin
|
||||
}
|
||||
|
||||
config.TCPAll.DenyPorts = params.TcpAllDenyPorts
|
||||
config.TCPAll.PortRangeMin = params.TcpAllPortRangeMin
|
||||
config.TCPAll.PortRangeMax = params.TcpAllPortRangeMax
|
||||
|
||||
// 性能
|
||||
config.Performance.AutoReadTimeout = params.PerformanceAutoReadTimeout
|
||||
config.Performance.AutoWriteTimeout = params.PerformanceAutoWriteTimeout
|
||||
config.Performance.Debug = params.PerformanceDebug
|
||||
|
||||
err = config.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
configJSON, err = json.Marshal(config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterGlobalServerConfig(this.AdminContext(), &pb.UpdateNodeClusterGlobalServerConfigRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
GlobalServerConfigJSON: configJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package health
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CheckDomainAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CheckDomainAction) RunPost(params struct {
|
||||
Host string
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["isOk"] = true // 默认为TRUE
|
||||
|
||||
var host = params.Host
|
||||
if len(host) > 0 &&
|
||||
!strings.Contains(host, "{") /** 包含变量 **/ {
|
||||
h, _, err := net.SplitHostPort(host)
|
||||
if err == nil && len(h) > 0 {
|
||||
host = h
|
||||
}
|
||||
|
||||
// 是否为IP
|
||||
if net.ParseIP(host) != nil {
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
host = strings.ToLower(host)
|
||||
resp, err := this.RPC().ServerRPC().CheckServerNameDuplicationInNodeCluster(this.AdminContext(), &pb.CheckServerNameDuplicationInNodeClusterRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
ServerNames: []string{host},
|
||||
SupportWildcard: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(resp.DuplicatedServerNames) == 0 {
|
||||
this.Data["isOk"] = false
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package health
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("health")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
configResp, err := this.RPC().NodeClusterRPC().FindNodeClusterHealthCheckConfig(this.AdminContext(), &pb.FindNodeClusterHealthCheckConfigRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var config *serverconfigs.HealthCheckConfig = nil
|
||||
if len(configResp.HealthCheckJSON) > 0 {
|
||||
config = &serverconfigs.HealthCheckConfig{}
|
||||
err = json.Unmarshal(configResp.HealthCheckJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["healthCheckConfig"] = config
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
HealthCheckJSON []byte
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeCluster_LogUpdateClusterHealthCheck, params.ClusterId)
|
||||
|
||||
config := &serverconfigs.HealthCheckConfig{}
|
||||
err := json.Unmarshal(params.HealthCheckJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterHealthCheck(this.AdminContext(), &pb.UpdateNodeClusterHealthCheckRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
HealthCheckJSON: params.HealthCheckJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package health
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type RunPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *RunPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *RunPopupAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
// 检查是否已部署服务
|
||||
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithNodeClusterId(this.AdminContext(), &pb.CountAllEnabledServersWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["hasServers"] = countServersResp.Count > 0
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *RunPopupAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeCluster_LogRunClusterHealthCheck, params.ClusterId)
|
||||
|
||||
resp, err := this.RPC().NodeClusterRPC().ExecuteNodeClusterHealthCheck(this.AdminContext(), &pb.ExecuteNodeClusterHealthCheckRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.Fail(err.Error())
|
||||
}
|
||||
|
||||
if resp.Results == nil {
|
||||
resp.Results = []*pb.ExecuteNodeClusterHealthCheckResponse_Result{}
|
||||
}
|
||||
this.Data["results"] = resp.Results
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package http3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "index")
|
||||
this.SecondMenu("http3")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
http3Resp, err := this.RPC().NodeClusterRPC().FindNodeClusterHTTP3Policy(this.AdminContext(), &pb.FindNodeClusterHTTP3PolicyRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(http3Resp.Http3PolicyJSON) == 0 {
|
||||
this.Data["http3Policy"] = nodeconfigs.NewHTTP3Policy()
|
||||
} else {
|
||||
var config = nodeconfigs.NewHTTP3Policy()
|
||||
err = json.Unmarshal(http3Resp.Http3PolicyJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["http3Policy"] = config
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
IsOn bool
|
||||
Port int
|
||||
SupportMobileBrowsers bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ServerHTTP3_LogUpdateClusterHTTP3Policy, params.ClusterId)
|
||||
|
||||
if params.Port <= 0 || params.Port > 1024 {
|
||||
this.FailField("port", "请输入1-1024之间的端口号")
|
||||
return
|
||||
}
|
||||
|
||||
var config = nodeconfigs.NewHTTP3Policy()
|
||||
config.IsOn = params.IsOn
|
||||
config.Port = params.Port
|
||||
config.SupportMobileBrowsers = params.SupportMobileBrowsers
|
||||
|
||||
err := config.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:")
|
||||
}
|
||||
|
||||
configJSON, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterHTTP3Policy(this.AdminContext(), &pb.UpdateNodeClusterHTTP3PolicyRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Http3PolicyJSON: configJSON,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package http3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/taskutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) Init() {
|
||||
this.Nav("", "setting", "test")
|
||||
this.SecondMenu("http3")
|
||||
}
|
||||
|
||||
func (this *TestAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
http3Resp, err := this.RPC().NodeClusterRPC().FindNodeClusterHTTP3Policy(this.AdminContext(), &pb.FindNodeClusterHTTP3PolicyRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(http3Resp.Http3PolicyJSON) == 0 {
|
||||
this.Data["http3Policy"] = nodeconfigs.NewHTTP3Policy()
|
||||
} else {
|
||||
var config = nodeconfigs.NewHTTP3Policy()
|
||||
err = json.Unmarshal(http3Resp.Http3PolicyJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["http3Policy"] = config
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Port int
|
||||
|
||||
URL string `alias:"url"`
|
||||
}) {
|
||||
var testingURL = params.URL
|
||||
if len(testingURL) == 0 {
|
||||
this.FailField("url", "请输入测试网址")
|
||||
return
|
||||
}
|
||||
|
||||
u, err := url.Parse(testingURL)
|
||||
if err != nil {
|
||||
this.FailField("url", "测试网址格式不正确")
|
||||
return
|
||||
}
|
||||
if u.Scheme != "https" {
|
||||
this.FailField("url", "测试网址必须以https://开头")
|
||||
return
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
NodeId int64 `json:"nodeId"`
|
||||
NodeName string `json:"nodeName"`
|
||||
IP string `json:"ip"`
|
||||
IsOk bool `json:"isOk"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
var results = []*Result{}
|
||||
|
||||
nodesResp, err := this.RPC().NodeRPC().FindAllEnabledNodesWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodesWithNodeClusterIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
IncludeSecondary: false,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, node := range nodesResp.Nodes {
|
||||
if !node.IsOn {
|
||||
continue
|
||||
}
|
||||
addrsResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: node.Id,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, addr := range addrsResp.NodeIPAddresses {
|
||||
if !addr.IsOn || !addr.CanAccess {
|
||||
continue
|
||||
}
|
||||
results = append(results, &Result{
|
||||
NodeId: node.Id,
|
||||
NodeName: node.Name,
|
||||
IP: addr.Ip,
|
||||
IsOk: false,
|
||||
Error: "",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var totalResults = len(results)
|
||||
|
||||
if totalResults == 0 {
|
||||
this.Data["results"] = results
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
err = taskutils.RunConcurrent(results, 16, func(task any) {
|
||||
var result = task.(*Result)
|
||||
|
||||
var client = &http.Client{
|
||||
Transport: &http3.RoundTripper{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
||||
var realAddr = configutils.QuoteIP(result.IP) + ":" + types.String(params.Port)
|
||||
return quic.DialAddrEarly(ctx, realAddr, tlsCfg, cfg)
|
||||
},
|
||||
},
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
defer client.CloseIdleConnections()
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, testingURL, nil)
|
||||
if err != nil {
|
||||
result.Error = "validate url failed: " + err.Error()
|
||||
return
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
result.Error = "request url failed: " + err.Error()
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
|
||||
result.IsOk = true
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["results"] = results
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("basic")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
// 基本信息
|
||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cluster := clusterResp.NodeCluster
|
||||
if cluster == nil {
|
||||
this.WriteString("not found cluster")
|
||||
return
|
||||
}
|
||||
|
||||
// 认证
|
||||
var grantMap interface{} = nil
|
||||
|
||||
if cluster.NodeGrantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: cluster.NodeGrantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var grant = grantResp.NodeGrant
|
||||
if grant != nil {
|
||||
grantMap = maps.Map{
|
||||
"id": grant.Id,
|
||||
"name": grant.Name,
|
||||
"method": grant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grant.Method, this.LangCode()),
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["grant"] = grantMap
|
||||
|
||||
// 时区
|
||||
this.Data["timeZoneGroups"] = nodeconfigs.FindAllTimeZoneGroups()
|
||||
this.Data["timeZoneLocations"] = nodeconfigs.FindAllTimeZoneLocations()
|
||||
|
||||
if len(cluster.TimeZone) == 0 {
|
||||
cluster.TimeZone = nodeconfigs.DefaultTimeZoneLocation
|
||||
}
|
||||
this.Data["timeZoneLocation"] = nodeconfigs.FindTimeZoneLocation(cluster.TimeZone)
|
||||
|
||||
// 时钟
|
||||
var clockConfig = nodeconfigs.DefaultClockConfig()
|
||||
if len(cluster.ClockJSON) > 0 {
|
||||
err = json.Unmarshal(cluster.ClockJSON, clockConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if clockConfig == nil {
|
||||
clockConfig = nodeconfigs.DefaultClockConfig()
|
||||
}
|
||||
}
|
||||
|
||||
// SSH参数
|
||||
var sshParams = nodeconfigs.DefaultSSHParams()
|
||||
if len(cluster.SshParamsJSON) > 0 {
|
||||
err = json.Unmarshal(cluster.SshParamsJSON, sshParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DNS信息
|
||||
var fullDomainName = ""
|
||||
if len(cluster.DnsName) > 0 && cluster.DnsDomainId > 0 {
|
||||
domainResp, err := this.RPC().DNSDomainRPC().FindBasicDNSDomain(this.AdminContext(), &pb.FindBasicDNSDomainRequest{DnsDomainId: cluster.DnsDomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if domainResp.DnsDomain != nil {
|
||||
fullDomainName = cluster.DnsName + "." + domainResp.DnsDomain.Name
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["cluster"] = maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"installDir": cluster.InstallDir,
|
||||
"timeZone": cluster.TimeZone,
|
||||
"nodeMaxThreads": cluster.NodeMaxThreads,
|
||||
"autoOpenPorts": cluster.AutoOpenPorts,
|
||||
"clock": clockConfig,
|
||||
"autoRemoteStart": cluster.AutoRemoteStart,
|
||||
"autoInstallNftables": cluster.AutoInstallNftables,
|
||||
"autoSystemTuning": cluster.AutoSystemTuning,
|
||||
"autoTrimDisks": cluster.AutoTrimDisks,
|
||||
"maxConcurrentReads": cluster.MaxConcurrentReads,
|
||||
"maxConcurrentWrites": cluster.MaxConcurrentWrites,
|
||||
"sshParams": sshParams,
|
||||
"domainName": fullDomainName,
|
||||
}
|
||||
|
||||
// 默认值
|
||||
this.Data["defaultNodeMaxThreads"] = nodeconfigs.DefaultMaxThreads
|
||||
this.Data["defaultNodeMaxThreadsMin"] = nodeconfigs.DefaultMaxThreadsMin
|
||||
this.Data["defaultNodeMaxThreadsMax"] = nodeconfigs.DefaultMaxThreadsMax
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
// RunPost 保存设置
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Name string
|
||||
GrantId int64
|
||||
SshParamsPort int
|
||||
InstallDir string
|
||||
TimeZone string
|
||||
NodeMaxThreads int32
|
||||
AutoOpenPorts bool
|
||||
ClockAutoSync bool
|
||||
ClockServer string
|
||||
ClockCheckChrony bool
|
||||
AutoRemoteStart bool
|
||||
AutoInstallNftables bool
|
||||
AutoSystemTuning bool
|
||||
AutoTrimDisks bool
|
||||
MaxConcurrentReads int32
|
||||
MaxConcurrentWrites int32
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeCluster_LogUpdateClusterBasicSettings, params.ClusterId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入集群名称")
|
||||
|
||||
if params.NodeMaxThreads > 0 {
|
||||
params.Must.
|
||||
Field("nodeMaxThreads", params.NodeMaxThreads).
|
||||
Gte(int64(nodeconfigs.DefaultMaxThreadsMin), "单节点最大线程数最小值不能小于"+types.String(nodeconfigs.DefaultMaxThreadsMin)).
|
||||
Lte(int64(nodeconfigs.DefaultMaxThreadsMax), "单节点最大线程数最大值不能大于"+types.String(nodeconfigs.DefaultMaxThreadsMax))
|
||||
}
|
||||
|
||||
// ssh
|
||||
var sshParams = nodeconfigs.DefaultSSHParams()
|
||||
sshParams.Port = params.SshParamsPort
|
||||
sshParamsJSON, err := json.Marshal(sshParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// clock
|
||||
var clockConfig = nodeconfigs.DefaultClockConfig()
|
||||
clockConfig.AutoSync = params.ClockAutoSync
|
||||
clockConfig.Server = params.ClockServer
|
||||
clockConfig.CheckChrony = params.ClockCheckChrony
|
||||
clockConfigJSON, err := json.Marshal(clockConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = clockConfig.Init()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeCluster(this.AdminContext(), &pb.UpdateNodeClusterRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
NodeGrantId: params.GrantId,
|
||||
InstallDir: params.InstallDir,
|
||||
TimeZone: params.TimeZone,
|
||||
NodeMaxThreads: params.NodeMaxThreads,
|
||||
AutoOpenPorts: params.AutoOpenPorts,
|
||||
ClockJSON: clockConfigJSON,
|
||||
AutoRemoteStart: params.AutoRemoteStart,
|
||||
AutoInstallNftables: params.AutoInstallNftables,
|
||||
AutoSystemTuning: params.AutoSystemTuning,
|
||||
AutoTrimDisks: params.AutoTrimDisks,
|
||||
SshParamsJSON: sshParamsJSON,
|
||||
MaxConcurrentReads: params.MaxConcurrentReads,
|
||||
MaxConcurrentWrites: params.MaxConcurrentWrites,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/cache"
|
||||
ddosProtection "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/ddos-protection"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/dns"
|
||||
firewallActions "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/firewall-actions"
|
||||
globalServerConfig "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/global-server-config"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/health"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/metrics"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/services"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/waf"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/webp"
|
||||
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNode)).
|
||||
Helper(clusters.NewClusterHelper()).
|
||||
Prefix("/clusters/cluster/settings").
|
||||
Data("teaSubMenu", "cluster").
|
||||
GetPost("", new(IndexAction)).
|
||||
|
||||
// 健康检查
|
||||
GetPost("/health", new(health.IndexAction)).
|
||||
GetPost("/health/runPopup", new(health.RunPopupAction)).
|
||||
Post("/health/checkDomain", new(health.CheckDomainAction)).
|
||||
|
||||
// 缓存
|
||||
GetPost("/cache", new(cache.IndexAction)).
|
||||
|
||||
// WAF
|
||||
GetPost("/waf", new(waf.IndexAction)).
|
||||
|
||||
// DNS
|
||||
Prefix("/clusters/cluster/settings/dns").
|
||||
GetPost("", new(dns.IndexAction)).
|
||||
Get("/records", new(dns.RecordsAction)).
|
||||
Post("/randomName", new(dns.RandomNameAction)).
|
||||
|
||||
// 系统服务设置
|
||||
Prefix("/clusters/cluster/settings/services").
|
||||
GetPost("", new(services.IndexAction)).
|
||||
GetPost("/status", new(services.StatusAction)).
|
||||
|
||||
// 防火墙动作
|
||||
Prefix("/clusters/cluster/settings/firewall-actions").
|
||||
Get("", new(firewallActions.IndexAction)).
|
||||
GetPost("/createPopup", new(firewallActions.CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(firewallActions.UpdatePopupAction)).
|
||||
Post("/delete", new(firewallActions.DeleteAction)).
|
||||
|
||||
// 指标
|
||||
Prefix("/clusters/cluster/settings/metrics").
|
||||
Get("", new(metrics.IndexAction)).
|
||||
GetPost("/createPopup", new(metrics.CreatePopupAction)).
|
||||
Post("/delete", new(metrics.DeleteAction)).
|
||||
|
||||
// WebP
|
||||
Prefix("/clusters/cluster/settings/webp").
|
||||
GetPost("", new(webp.IndexAction)).
|
||||
|
||||
// DDOS Protection
|
||||
Prefix("/clusters/cluster/settings/ddos-protection").
|
||||
GetPost("", new(ddosProtection.IndexAction)).
|
||||
GetPost("/status", new(ddosProtection.StatusAction)).
|
||||
|
||||
// 全局服务配置
|
||||
Prefix("/clusters/cluster/settings/global-server-config").
|
||||
GetPost("", new(globalServerConfig.IndexAction)).
|
||||
|
||||
//
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package settings
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/message"
|
||||
schedulesettings "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/schedule"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/thresholds"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/toa"
|
||||
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNode)).
|
||||
Helper(clusters.NewClusterHelper()).
|
||||
Data("teaSubMenu", "cluster").
|
||||
Prefix("/clusters/cluster/settings").
|
||||
|
||||
// 消息
|
||||
Prefix("/clusters/cluster/settings/message").
|
||||
GetPost("", new(message.IndexAction)).
|
||||
Get("/selectReceiverPopup", new(message.SelectReceiverPopupAction)).
|
||||
Post("/selectedReceivers", new(message.SelectedReceiversAction)).
|
||||
|
||||
// 阈值
|
||||
Prefix("/clusters/cluster/settings/thresholds").
|
||||
Get("", new(thresholds.IndexAction)).
|
||||
GetPost("/createPopup", new(thresholds.CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(thresholds.UpdatePopupAction)).
|
||||
Post("/delete", new(thresholds.DeleteAction)).
|
||||
|
||||
// 智能调度
|
||||
Prefix("/clusters/cluster/settings/schedule").
|
||||
Get("", new(schedulesettings.IndexAction)).
|
||||
|
||||
// TOA
|
||||
Prefix("/clusters/cluster/settings/toa").
|
||||
GetPost("", new(toa.IndexAction)).
|
||||
|
||||
//
|
||||
EndAll()
|
||||
})
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//go:build plus
|
||||
|
||||
package message
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("message")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
ReceiversJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.MessageReceiver_LogUpdateClusterMessageReceivers, params.ClusterId)
|
||||
|
||||
receiverMaps := []maps.Map{}
|
||||
if len(params.ReceiversJSON) > 0 {
|
||||
err := json.Unmarshal(params.ReceiversJSON, &receiverMaps)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
pbReceiverOptions := &pb.UpdateMessageReceiversRequest_RecipientOptions{}
|
||||
for _, receiverMap := range receiverMaps {
|
||||
recipientId := int64(0)
|
||||
groupId := int64(0)
|
||||
receiverType := receiverMap.GetString("type")
|
||||
switch receiverType {
|
||||
case "recipient":
|
||||
recipientId = receiverMap.GetInt64("id")
|
||||
case "group":
|
||||
groupId = receiverMap.GetInt64("id")
|
||||
default:
|
||||
continue
|
||||
}
|
||||
pbReceiverOptions.RecipientOptions = append(pbReceiverOptions.RecipientOptions, &pb.UpdateMessageReceiversRequest_RecipientOption{
|
||||
MessageRecipientId: recipientId,
|
||||
MessageRecipientGroupId: groupId,
|
||||
})
|
||||
}
|
||||
|
||||
_, err := this.RPC().MessageReceiverRPC().UpdateMessageReceivers(this.AdminContext(), &pb.UpdateMessageReceiversRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: 0,
|
||||
ServerId: 0,
|
||||
ParamsJSON: nil,
|
||||
RecipientOptions: map[string]*pb.UpdateMessageReceiversRequest_RecipientOptions{
|
||||
"*": pbReceiverOptions,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
//go:build plus
|
||||
|
||||
package message
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectReceiverPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectReceiverPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectReceiverPopupAction) RunGet(params struct {
|
||||
RecipientIds string
|
||||
GroupIds string
|
||||
}) {
|
||||
recipientIds := utils.SplitNumbers(params.RecipientIds)
|
||||
groupIds := utils.SplitNumbers(params.GroupIds)
|
||||
|
||||
// 所有接收人
|
||||
recipientsResp, err := this.RPC().MessageRecipientRPC().ListEnabledMessageRecipients(this.AdminContext(), &pb.ListEnabledMessageRecipientsRequest{
|
||||
AdminId: 0,
|
||||
MediaType: "",
|
||||
MessageRecipientGroupId: 0,
|
||||
Keyword: "",
|
||||
Offset: 0,
|
||||
Size: 1000, // TODO 支持搜索
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
recipientMaps := []maps.Map{}
|
||||
for _, recipient := range recipientsResp.MessageRecipients {
|
||||
if !recipient.IsOn {
|
||||
continue
|
||||
}
|
||||
if lists.ContainsInt64(recipientIds, recipient.Id) {
|
||||
continue
|
||||
}
|
||||
recipientMaps = append(recipientMaps, maps.Map{
|
||||
"id": recipient.Id,
|
||||
"name": recipient.Admin.Fullname,
|
||||
"instanceName": recipient.MessageMediaInstance.Name,
|
||||
})
|
||||
}
|
||||
this.Data["recipients"] = recipientMaps
|
||||
|
||||
// 所有分组
|
||||
groupsResp, err := this.RPC().MessageRecipientGroupRPC().FindAllEnabledMessageRecipientGroups(this.AdminContext(), &pb.FindAllEnabledMessageRecipientGroupsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.MessageRecipientGroups {
|
||||
if !group.IsOn {
|
||||
continue
|
||||
}
|
||||
if lists.ContainsInt64(groupIds, group.Id) {
|
||||
continue
|
||||
}
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package message
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectedReceiversAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectedReceiversAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectedReceiversAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
ServerId int64
|
||||
}) {
|
||||
receiversResp, err := this.RPC().MessageReceiverRPC().FindAllEnabledMessageReceivers(this.AdminContext(), &pb.FindAllEnabledMessageReceiversRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: params.NodeId,
|
||||
ServerId: params.ServerId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
receiverMaps := []maps.Map{}
|
||||
for _, receiver := range receiversResp.MessageReceivers {
|
||||
id := int64(0)
|
||||
name := ""
|
||||
receiverType := ""
|
||||
subName := ""
|
||||
if receiver.MessageRecipient != nil {
|
||||
id = receiver.MessageRecipient.Id
|
||||
name = receiver.MessageRecipient.Admin.Fullname
|
||||
subName = receiver.MessageRecipient.MessageMediaInstance.Name
|
||||
receiverType = "recipient"
|
||||
} else if receiver.MessageRecipientGroup != nil {
|
||||
id = receiver.MessageRecipientGroup.Id
|
||||
name = receiver.MessageRecipientGroup.Name
|
||||
receiverType = "group"
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
receiverMaps = append(receiverMaps, maps.Map{
|
||||
"id": id,
|
||||
"name": name,
|
||||
"subName": subName,
|
||||
"type": receiverType,
|
||||
})
|
||||
}
|
||||
this.Data["receivers"] = receiverMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
Category string
|
||||
}) {
|
||||
if len(params.Category) == 0 {
|
||||
params.Category = "http"
|
||||
}
|
||||
this.Data["category"] = params.Category
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
|
||||
countResp, err := this.RPC().MetricItemRPC().CountAllEnabledMetricItems(this.AdminContext(), &pb.CountAllEnabledMetricItemsRequest{Category: params.Category})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
itemsResp, err := this.RPC().MetricItemRPC().ListEnabledMetricItems(this.AdminContext(), &pb.ListEnabledMetricItemsRequest{
|
||||
Category: params.Category,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var itemMaps = []maps.Map{}
|
||||
for _, item := range itemsResp.MetricItems {
|
||||
// 是否已添加
|
||||
existsResp, err := this.RPC().NodeClusterMetricItemRPC().ExistsNodeClusterMetricItem(this.AdminContext(), &pb.ExistsNodeClusterMetricItemRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
MetricItemId: item.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var exists = existsResp.Exists
|
||||
|
||||
itemMaps = append(itemMaps, maps.Map{
|
||||
"id": item.Id,
|
||||
"name": item.Name,
|
||||
"code": item.Code,
|
||||
"isOn": item.IsOn,
|
||||
"period": item.Period,
|
||||
"periodUnit": item.PeriodUnit,
|
||||
"periodUnitName": serverconfigs.FindMetricPeriodUnitName(item.PeriodUnit),
|
||||
"keys": item.Keys,
|
||||
"value": item.Value,
|
||||
"valueName": serverconfigs.FindMetricValueName(item.Category, item.Value),
|
||||
"category": item.Category,
|
||||
"isPublic": item.IsPublic,
|
||||
"isChecked": exists,
|
||||
})
|
||||
}
|
||||
this.Data["items"] = itemMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
ItemId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.MetricItem_LogAddMetricItemToCluster, params.ItemId, params.ClusterId)
|
||||
|
||||
_, err := this.RPC().NodeClusterMetricItemRPC().EnableNodeClusterMetricItem(this.AdminContext(), &pb.EnableNodeClusterMetricItemRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
MetricItemId: params.ItemId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
ItemId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.MetricItem_LogDeleteMetricItemFromCluster, params.ClusterId, params.ItemId)
|
||||
|
||||
_, err := this.RPC().NodeClusterMetricItemRPC().DisableNodeClusterMetricItem(this.AdminContext(), &pb.DisableNodeClusterMetricItemRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
MetricItemId: params.ItemId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "setting")
|
||||
this.SecondMenu("metric")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
Category string
|
||||
}) {
|
||||
if len(params.Category) == 0 {
|
||||
params.Category = "http"
|
||||
}
|
||||
this.Data["category"] = params.Category
|
||||
|
||||
itemsResp, err := this.RPC().NodeClusterMetricItemRPC().FindAllNodeClusterMetricItems(this.AdminContext(), &pb.FindAllNodeClusterMetricItemsRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Category: params.Category,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var itemMaps = []maps.Map{}
|
||||
for _, item := range itemsResp.MetricItems {
|
||||
itemMaps = append(itemMaps, maps.Map{
|
||||
"id": item.Id,
|
||||
"name": item.Name,
|
||||
"code": item.Code,
|
||||
"isOn": item.IsOn,
|
||||
"period": item.Period,
|
||||
"periodUnit": item.PeriodUnit,
|
||||
"periodUnitName": serverconfigs.FindMetricPeriodUnitName(item.PeriodUnit),
|
||||
"keys": item.Keys,
|
||||
"value": item.Value,
|
||||
"valueName": serverconfigs.FindMetricValueName(item.Category, item.Value),
|
||||
"category": item.Category,
|
||||
"isPublic": item.IsPublic,
|
||||
})
|
||||
}
|
||||
this.Data["items"] = itemMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package networksecurity
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"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"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "index")
|
||||
this.SecondMenu("networkSecurity")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
policyResp, err := this.RPC().NodeClusterRPC().FindNodeClusterNetworkSecurityPolicy(this.AdminContext(), &pb.FindNodeClusterNetworkSecurityPolicyRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var policy = nodeconfigs.NewNetworkSecurityPolicy()
|
||||
if len(policyResp.NetworkSecurityPolicyJSON) > 0 {
|
||||
err = json.Unmarshal(policyResp.NetworkSecurityPolicyJSON, policy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["policy"] = policy
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Status string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
policyResp, err := this.RPC().NodeClusterRPC().FindNodeClusterNetworkSecurityPolicy(this.AdminContext(), &pb.FindNodeClusterNetworkSecurityPolicyRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var policy = nodeconfigs.NewNetworkSecurityPolicy()
|
||||
if len(policyResp.NetworkSecurityPolicyJSON) > 0 {
|
||||
err = json.Unmarshal(policyResp.NetworkSecurityPolicyJSON, policy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
policy.Status = params.Status
|
||||
|
||||
err = policy.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
policyJSON, err := json.Marshal(policy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterNetworkSecurityPolicy(this.AdminContext(), &pb.UpdateNodeClusterNetworkSecurityPolicyRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NetworkSecurityPolicyJSON: policyJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package pages
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("pages")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
if !teaconst.IsPlus {
|
||||
return
|
||||
}
|
||||
|
||||
pagesResp, err := this.RPC().NodeClusterRPC().FindNodeClusterHTTPPagesPolicy(this.AdminContext(), &pb.FindNodeClusterHTTPPagesPolicyRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(pagesResp.HttpPagesPolicyJSON) == 0 {
|
||||
this.Data["pagesPolicy"] = nodeconfigs.NewHTTPPagesPolicy()
|
||||
} else {
|
||||
var config = nodeconfigs.NewHTTPPagesPolicy()
|
||||
err = json.Unmarshal(pagesResp.HttpPagesPolicyJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["pagesPolicy"] = config
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
IsOn bool
|
||||
PagesJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ServerPage_LogUpdateClusterPages, params.ClusterId)
|
||||
|
||||
var pagePolicy = nodeconfigs.NewHTTPPagesPolicy()
|
||||
pagePolicy.IsOn = params.IsOn
|
||||
|
||||
err := json.Unmarshal(params.PagesJSON, &pagePolicy.Pages)
|
||||
if err != nil {
|
||||
this.Fail("解析配置失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = pagePolicy.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验配置失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
pagePolicyJSON, err := json.Marshal(pagePolicy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterHTTPPagesPolicy(this.AdminContext(), &pb.UpdateNodeClusterHTTPPagesPolicyRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
HttpPagesPolicyJSON: pagePolicyJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package schedulesettings
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"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"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "setting")
|
||||
this.SecondMenu("schedule")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
// 当前集群信息
|
||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var cluster = clusterResp.NodeCluster
|
||||
if cluster == nil {
|
||||
this.NotFound("nodeCluster", params.ClusterId)
|
||||
return
|
||||
}
|
||||
|
||||
// 节点信息
|
||||
nodesResp, err := this.RPC().NodeRPC().FindAllNodeScheduleInfoWithNodeClusterId(this.AdminContext(), &pb.FindAllNodeScheduleInfoWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 排序
|
||||
var pbNodes = nodesResp.Nodes
|
||||
sort.Slice(pbNodes, func(i, j int) bool {
|
||||
var backup1 = 0
|
||||
var backup2 = 0
|
||||
if pbNodes[i].IsBackupForCluster || pbNodes[i].IsBackupForGroup {
|
||||
backup1 = 0
|
||||
}
|
||||
if pbNodes[j].IsBackupForCluster || pbNodes[j].IsBackupForGroup {
|
||||
backup2 = 0
|
||||
}
|
||||
|
||||
if backup1 != backup2 {
|
||||
return backup1 > backup2
|
||||
}
|
||||
|
||||
return pbNodes[i].NodeId < pbNodes[j].NodeId
|
||||
})
|
||||
|
||||
var nodeMaps = []maps.Map{}
|
||||
for _, node := range pbNodes {
|
||||
// 是否已下线
|
||||
var isOffline = len(node.OfflineDay) > 0 && node.OfflineDay < timeutil.Format("Ymd")
|
||||
|
||||
// 备用IP
|
||||
if node.BackupIPs == nil {
|
||||
node.BackupIPs = []string{}
|
||||
}
|
||||
|
||||
// 当前动作状态
|
||||
var actionStatus = &nodeconfigs.NodeActionStatus{}
|
||||
if len(node.ActionStatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.ActionStatusJSON, actionStatus)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"clusterName": cluster.Name,
|
||||
"clusterId": cluster.Id,
|
||||
"nodeId": node.NodeId,
|
||||
"nodeName": node.NodeName,
|
||||
"groupId": node.NodeGroupId,
|
||||
"groupName": node.NodeGroupName,
|
||||
"offlineDay": node.OfflineDay,
|
||||
"isOffline": isOffline,
|
||||
"isBackupForCluster": node.IsBackupForCluster,
|
||||
"isBackupForGroup": node.IsBackupForGroup,
|
||||
"backupIPs": node.BackupIPs,
|
||||
"actionStatus": actionStatus,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "setting")
|
||||
this.SecondMenu("service")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
serviceParamsResp, err := this.RPC().NodeClusterRPC().FindNodeClusterSystemService(this.AdminContext(), &pb.FindNodeClusterSystemServiceRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Type: nodeconfigs.SystemServiceTypeSystemd,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
paramsJSON := serviceParamsResp.ParamsJSON
|
||||
if len(paramsJSON) == 0 {
|
||||
this.Data["systemdIsOn"] = false
|
||||
} else {
|
||||
config := &nodeconfigs.SystemdServiceConfig{}
|
||||
err = json.Unmarshal(paramsJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["systemdIsOn"] = config.IsOn
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
SystemdIsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeSystemd_LogUpdateClusterSystemdSettings, params.ClusterId)
|
||||
|
||||
serviceParams := &nodeconfigs.SystemdServiceConfig{
|
||||
IsOn: params.SystemdIsOn,
|
||||
}
|
||||
serviceParamsJSON, err := json.Marshal(serviceParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterSystemService(this.AdminContext(), &pb.UpdateNodeClusterSystemServiceRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Type: nodeconfigs.SystemServiceTypeSystemd,
|
||||
ParamsJSON: serviceParamsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type StatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StatusAction) Init() {
|
||||
this.Nav("", "setting", "status")
|
||||
this.SecondMenu("service")
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunGet(params struct {
|
||||
}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeCheckSystemdService, &messageconfigs.CheckSystemdServiceMessage{}, 10, false)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["results"] = results
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package thresholds
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["items"] = nodeconfigs.FindAllNodeValueItemDefinitions()
|
||||
this.Data["operators"] = nodeconfigs.FindAllNodeValueOperatorDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
Item string
|
||||
Param string
|
||||
SumMethod string
|
||||
Operator string
|
||||
Value string
|
||||
Duration int32
|
||||
DurationUnit string
|
||||
Message string
|
||||
NotifyDuration int32
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
if params.ClusterId <= 0 && params.NodeId >= 0 {
|
||||
this.Fail("集群或者节点至少需要填写其中一个参数")
|
||||
}
|
||||
|
||||
valueJSON, err := json.Marshal(params.Value)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
resp, err := this.RPC().NodeThresholdRPC().CreateNodeThreshold(this.AdminContext(), &pb.CreateNodeThresholdRequest{
|
||||
Role: "node",
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: params.NodeId,
|
||||
Item: params.Item,
|
||||
Param: params.Param,
|
||||
Operator: params.Operator,
|
||||
ValueJSON: valueJSON,
|
||||
Message: params.Message,
|
||||
Duration: params.Duration,
|
||||
DurationUnit: params.DurationUnit,
|
||||
SumMethod: params.SumMethod,
|
||||
NotifyDuration: params.NotifyDuration,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
defer this.CreateLogInfo(codes.NodeThreshold_LogCreateNodeThreshold, resp.NodeThresholdId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package thresholds
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
// DeleteAction 删除阈值
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
ThresholdId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeThreshold_LogDeleteNodeThreshold, params.ThresholdId)
|
||||
|
||||
_, err := this.RPC().NodeThresholdRPC().DeleteNodeThreshold(this.AdminContext(), &pb.DeleteNodeThresholdRequest{NodeThresholdId: params.ThresholdId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package thresholds
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "setting")
|
||||
this.SecondMenu("threshold")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
// 列出所有阈值
|
||||
thresholdsResp, err := this.RPC().NodeThresholdRPC().FindAllEnabledNodeThresholds(this.AdminContext(), &pb.FindAllEnabledNodeThresholdsRequest{
|
||||
Role: "node",
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
thresholdMaps := []maps.Map{}
|
||||
for _, threshold := range thresholdsResp.NodeThresholds {
|
||||
var nodeMap maps.Map = nil
|
||||
if threshold.Node != nil {
|
||||
nodeMap = maps.Map{
|
||||
"id": threshold.Node.Id,
|
||||
"name": threshold.Node.Name,
|
||||
}
|
||||
}
|
||||
|
||||
thresholdMaps = append(thresholdMaps, maps.Map{
|
||||
"id": threshold.Id,
|
||||
"itemName": nodeconfigs.FindNodeValueItemName(threshold.Item),
|
||||
"paramName": nodeconfigs.FindNodeValueItemParamName(threshold.Item, threshold.Param),
|
||||
"paramIsPercent": nodeconfigs.CheckNodeValueItemParamIsPercent(threshold.Item, threshold.Param),
|
||||
"operatorName": nodeconfigs.FindNodeValueOperatorName(threshold.Operator),
|
||||
"value": nodeconfigs.UnmarshalNodeValue(threshold.ValueJSON),
|
||||
"sumMethodName": nodeconfigs.FindNodeValueSumMethodName(threshold.SumMethod),
|
||||
"duration": threshold.Duration,
|
||||
"durationUnitName": nodeconfigs.FindNodeValueDurationUnitName(threshold.DurationUnit),
|
||||
"isOn": threshold.IsOn,
|
||||
"node": nodeMap,
|
||||
})
|
||||
}
|
||||
this.Data["thresholds"] = thresholdMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package thresholds
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
ThresholdId int64
|
||||
}) {
|
||||
// 通用参数
|
||||
this.Data["items"] = nodeconfigs.FindAllNodeValueItemDefinitions()
|
||||
this.Data["operators"] = nodeconfigs.FindAllNodeValueOperatorDefinitions()
|
||||
|
||||
// 阈值详情
|
||||
thresholdResp, err := this.RPC().NodeThresholdRPC().FindEnabledNodeThreshold(this.AdminContext(), &pb.FindEnabledNodeThresholdRequest{NodeThresholdId: params.ThresholdId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
threshold := thresholdResp.NodeThreshold
|
||||
if threshold == nil {
|
||||
this.NotFound("nodeThreshold", params.ThresholdId)
|
||||
return
|
||||
}
|
||||
|
||||
valueInterface := new(interface{})
|
||||
err = json.Unmarshal(threshold.ValueJSON, valueInterface)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["threshold"] = maps.Map{
|
||||
"id": threshold.Id,
|
||||
"item": threshold.Item,
|
||||
"param": threshold.Param,
|
||||
"message": threshold.Message,
|
||||
"notifyDuration": threshold.NotifyDuration,
|
||||
"value": nodeconfigs.UnmarshalNodeValue(threshold.ValueJSON),
|
||||
"operator": threshold.Operator,
|
||||
"duration": threshold.Duration,
|
||||
"durationUnit": threshold.DurationUnit,
|
||||
"isOn": threshold.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
ThresholdId int64
|
||||
Item string
|
||||
Param string
|
||||
SumMethod string
|
||||
Operator string
|
||||
Value string
|
||||
Duration int32
|
||||
DurationUnit string
|
||||
Message string
|
||||
NotifyDuration int32
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeThreshold_LogUpdateNodeThreshold, params.ThresholdId)
|
||||
|
||||
valueJSON, err := json.Marshal(params.Value)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().NodeThresholdRPC().UpdateNodeThreshold(this.AdminContext(), &pb.UpdateNodeThresholdRequest{
|
||||
NodeThresholdId: params.ThresholdId,
|
||||
Item: params.Item,
|
||||
Param: params.Param,
|
||||
Operator: params.Operator,
|
||||
ValueJSON: valueJSON,
|
||||
Message: params.Message,
|
||||
NotifyDuration: params.NotifyDuration,
|
||||
Duration: params.Duration,
|
||||
DurationUnit: params.DurationUnit,
|
||||
SumMethod: params.SumMethod,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
//go:build plus
|
||||
|
||||
package toa
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("toa")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
if !teaconst.IsPlus {
|
||||
return
|
||||
}
|
||||
|
||||
toaResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterTOA(this.AdminContext(), &pb.FindEnabledNodeClusterTOARequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(toaResp.ToaJSON) == 0 {
|
||||
this.Data["toa"] = nodeconfigs.NewTOAConfig()
|
||||
} else {
|
||||
var config = nodeconfigs.NewTOAConfig()
|
||||
err = json.Unmarshal(toaResp.ToaJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["toa"] = config
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
IsOn bool
|
||||
AutoSetup bool
|
||||
OptionTypeV4 uint8
|
||||
OptionTypeV6 uint8
|
||||
MinQueueId uint8
|
||||
MaxQueueId uint8
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeTOA_LogUpdateClusterTOA, params.ClusterId)
|
||||
|
||||
var config = nodeconfigs.TOAConfig{
|
||||
IsOn: params.IsOn,
|
||||
Debug: false, // 暂时不允许打开调试
|
||||
OptionTypeV4: params.OptionTypeV4,
|
||||
OptionTypeV6: params.OptionTypeV6,
|
||||
MinQueueId: params.MinQueueId,
|
||||
AutoSetup: params.AutoSetup,
|
||||
}
|
||||
err := config.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置验证失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
configJSON, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterTOA(this.AdminContext(), &pb.UpdateNodeClusterTOARequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
ToaJSON: configJSON,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user