Initial commit (code only without large binaries)
This commit is contained in:
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()
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package uam
|
||||
|
||||
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", "")
|
||||
this.SecondMenu("uam")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
uamResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterUAMPolicy(this.AdminContext(), &pb.FindEnabledNodeClusterUAMPolicyRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(uamResp.UamPolicyJSON) == 0 {
|
||||
this.Data["uamPolicy"] = nodeconfigs.NewUAMPolicy()
|
||||
} else {
|
||||
var config = nodeconfigs.NewUAMPolicy()
|
||||
err = json.Unmarshal(uamResp.UamPolicyJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["uamPolicy"] = config
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
IsOn bool
|
||||
AllowSearchEngines bool
|
||||
DenySpiders bool
|
||||
MaxFails int
|
||||
BlockSeconds int
|
||||
IncludeSubdomains bool
|
||||
UITitle string `alias:"uiTitle"`
|
||||
UIBody string `alias:"uiBody"`
|
||||
KeyLife int
|
||||
FirewallScope string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ServerUAM_LogUpdateClusterUAMPolicy, params.ClusterId)
|
||||
|
||||
if params.KeyLife < 0 {
|
||||
params.KeyLife = 0
|
||||
}
|
||||
if params.MaxFails < 0 {
|
||||
params.MaxFails = 0
|
||||
}
|
||||
if params.BlockSeconds < 0 {
|
||||
params.BlockSeconds = 0
|
||||
}
|
||||
|
||||
var config = &nodeconfigs.UAMPolicy{
|
||||
IsOn: params.IsOn,
|
||||
AllowSearchEngines: params.AllowSearchEngines,
|
||||
DenySpiders: params.DenySpiders,
|
||||
UITitle: params.UITitle,
|
||||
UIBody: params.UIBody,
|
||||
KeyLife: params.KeyLife,
|
||||
MaxFails: params.MaxFails,
|
||||
BlockSeconds: params.BlockSeconds,
|
||||
IncludeSubdomains: params.IncludeSubdomains,
|
||||
}
|
||||
|
||||
// 防火墙
|
||||
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().UpdateNodeClusterUAMPolicy(this.AdminContext(), &pb.UpdateNodeClusterUAMPolicyRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
UamPolicyJSON: configJSON,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package waf
|
||||
|
||||
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("waf")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// WAF设置
|
||||
this.Data["firewallPolicy"] = nil
|
||||
if cluster.HttpFirewallPolicyId > 0 {
|
||||
firewallPolicy, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicy(this.AdminContext(), cluster.HttpFirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if firewallPolicy != nil {
|
||||
this.Data["firewallPolicy"] = maps.Map{
|
||||
"id": firewallPolicy.Id,
|
||||
"name": firewallPolicy.Name,
|
||||
"isOn": firewallPolicy.IsOn,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
HttpFirewallPolicyId int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.WAFPolicy_LogUpdateClusterWAFPolicy, params.ClusterId, params.HttpFirewallPolicyId)
|
||||
|
||||
if params.HttpFirewallPolicyId <= 0 {
|
||||
this.Fail("请选择WAF策略")
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeClusterRPC().UpdateNodeClusterHTTPFirewallPolicyId(this.AdminContext(), &pb.UpdateNodeClusterHTTPFirewallPolicyIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
HttpFirewallPolicyId: params.HttpFirewallPolicyId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package webp
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("webp")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
webpResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterWebPPolicy(this.AdminContext(), &pb.FindEnabledNodeClusterWebPPolicyRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(webpResp.WebpPolicyJSON) == 0 {
|
||||
this.Data["webpPolicy"] = nodeconfigs.DefaultWebPImagePolicy
|
||||
} else {
|
||||
var config = &nodeconfigs.WebPImagePolicy{}
|
||||
err = json.Unmarshal(webpResp.WebpPolicyJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["webpPolicy"] = config
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
IsOn bool
|
||||
Quality int
|
||||
RequireCache bool
|
||||
MinLengthJSON []byte
|
||||
MaxLengthJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ServerWebP_LogUpdateClusterWebPPolicy, params.ClusterId)
|
||||
|
||||
var config = &nodeconfigs.WebPImagePolicy{
|
||||
IsOn: params.IsOn,
|
||||
RequireCache: params.RequireCache,
|
||||
}
|
||||
|
||||
if params.Quality < 0 {
|
||||
params.Quality = 0
|
||||
} else if params.Quality > 100 {
|
||||
params.Quality = 100
|
||||
}
|
||||
config.Quality = params.Quality
|
||||
|
||||
if len(params.MinLengthJSON) > 0 {
|
||||
var minLength = &shared.SizeCapacity{}
|
||||
err := json.Unmarshal(params.MinLengthJSON, minLength)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
config.MinLength = minLength
|
||||
}
|
||||
|
||||
if len(params.MaxLengthJSON) > 0 {
|
||||
var maxLength = &shared.SizeCapacity{}
|
||||
err := json.Unmarshal(params.MaxLengthJSON, maxLength)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
config.MaxLength = maxLength
|
||||
}
|
||||
|
||||
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().UpdateNodeClusterWebPPolicy(this.AdminContext(), &pb.UpdateNodeClusterWebPPolicyRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
WebPPolicyJSON: configJSON,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
Reference in New Issue
Block a user