Compare commits

...

28 Commits

Author SHA1 Message Date
刘祥超
e4e3591413 修改文字 2021-09-24 12:03:31 +08:00
刘祥超
3f847d7c7f 区域监控增加检测时间、结果页增加级别筛选 2021-09-23 10:02:32 +08:00
刘祥超
67a10994a4 提示已经有服务分组配置时加入分组链接 2021-09-22 19:46:22 +08:00
刘祥超
4016296e0b 可以在分组中设置一些全局配置选项 2021-09-22 19:39:38 +08:00
刘祥超
92777366ec 域名解析任务列表中增加集群解析页面链接/在域名解析--集群详情中显示正在执行的任务 2021-09-21 10:56:29 +08:00
刘祥超
beb34f8264 可以设置集群的DNS记录TTL 2021-09-20 20:01:15 +08:00
刘祥超
f6f8c5c858 在集群中可以设置自动加入DNS的CNAME记录 2021-09-20 16:37:41 +08:00
刘祥超
a19c4dffcd 反向代理源站实现使用域名分组 2021-09-20 11:54:28 +08:00
刘祥超
a5754971f6 开源版本也显示域名排行、缓存流量趋势、攻击流量趋势 2021-09-19 16:10:52 +08:00
刘祥超
dbe6435809 实现连通性变化发送通知功能 2021-09-18 14:22:01 +08:00
刘祥超
7e5b980600 优化消息弹窗交互 2021-09-18 11:02:23 +08:00
刘祥超
a6c3b70ee7 修改生成的YAML配置中可能含有tab的Bug 2021-09-16 15:06:37 +08:00
刘祥超
0a23e7951a 增加商业版激活功能 2021-09-16 10:32:58 +08:00
刘祥超
e0e3fc8fef 看板提醒商业版过期日期 2021-09-16 09:21:44 +08:00
刘祥超
a8b947f5ca 修复日期控件初始化格式可能错误的问题 2021-09-15 19:40:42 +08:00
刘祥超
0f28df51f1 优化界面 2021-09-15 19:22:54 +08:00
刘祥超
6e36528f35 IP地址详情中增加区域监控雷达图、数据列表 2021-09-15 17:54:03 +08:00
刘祥超
a885fdbea7 修复IP地址不能修改在线状态的Bug 2021-09-15 11:46:50 +08:00
刘祥超
713de74abb 调整部分命名 2021-09-14 19:39:41 +08:00
刘祥超
8db6a33e15 IP阈值动作增加WebHook 2021-09-14 15:27:54 +08:00
刘祥超
ed2d577be0 IP阈值增加节点分组和集群相关统计项目 2021-09-14 11:36:08 +08:00
刘祥超
084eddecbf 优化节点设置交互 2021-09-13 16:47:34 +08:00
刘祥超
5e09ba302a IP地址支持手动上线和从备用IP中恢复 2021-09-13 13:45:39 +08:00
刘祥超
fa37b40435 实现节点自动切换到备用IP 2021-09-13 10:51:16 +08:00
刘祥超
c95dde5187 实现基础的IP地址阈值 2021-09-12 20:21:32 +08:00
刘祥超
4d5a4d501a 修复当集群没有绑定DNS域名时无法修改节点DNS信息的Bug 2021-09-11 20:12:06 +08:00
刘祥超
ce97f20826 实现基本的监控终端管理 2021-09-08 19:34:51 +08:00
刘祥超
ab9cd13abc 版本修改为0.3.1 2021-09-08 19:34:47 +08:00
210 changed files with 4930 additions and 1322 deletions

View File

@@ -1,9 +1,9 @@
package teaconst package teaconst
const ( const (
Version = "0.3.0" Version = "0.3.1"
APINodeVersion = "0.3.0" APINodeVersion = "0.3.1"
ProductName = "Edge Admin" ProductName = "Edge Admin"
ProcessName = "edge-admin" ProcessName = "edge-admin"

View File

@@ -103,6 +103,10 @@ func (this *RPCClient) NodeIPAddressLogRPC() pb.NodeIPAddressLogServiceClient {
return pb.NewNodeIPAddressLogServiceClient(this.pickConn()) return pb.NewNodeIPAddressLogServiceClient(this.pickConn())
} }
func (this *RPCClient) NodeIPAddressThresholdRPC() pb.NodeIPAddressThresholdServiceClient {
return pb.NewNodeIPAddressThresholdServiceClient(this.pickConn())
}
func (this *RPCClient) NodeValueRPC() pb.NodeValueServiceClient { func (this *RPCClient) NodeValueRPC() pb.NodeValueServiceClient {
return pb.NewNodeValueServiceClient(this.pickConn()) return pb.NewNodeValueServiceClient(this.pickConn())
} }
@@ -304,6 +308,10 @@ func (this *RPCClient) ReportNodeRPC() pb.ReportNodeServiceClient {
return pb.NewReportNodeServiceClient(this.pickConn()) return pb.NewReportNodeServiceClient(this.pickConn())
} }
func (this *RPCClient) ReportNodeGroupRPC() pb.ReportNodeGroupServiceClient {
return pb.NewReportNodeGroupServiceClient(this.pickConn())
}
func (this *RPCClient) ReportResultRPC() pb.ReportResultServiceClient { func (this *RPCClient) ReportResultRPC() pb.ReportResultServiceClient {
return pb.NewReportResultServiceClient(this.pickConn()) return pb.NewReportResultServiceClient(this.pickConn())
} }

View File

@@ -95,6 +95,7 @@ func (this *CreateBatchAction) RunPost(params struct {
Name: "IP地址", Name: "IP地址",
Ip: ip, Ip: ip,
CanAccess: true, CanAccess: true,
IsUp: true,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -167,32 +167,49 @@ func (this *CreateNodeAction) RunPost(params struct {
nodeId := createResp.NodeId nodeId := createResp.NodeId
// IP地址 // IP地址
for _, address := range ipAddresses { for _, addr := range ipAddresses {
addressId := address.GetInt64("id") addrId := addr.GetInt64("id")
if addressId > 0 { if addrId > 0 {
_, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{ _, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{
NodeIPAddressId: addressId, NodeIPAddressId: addrId,
NodeId: nodeId, NodeId: nodeId,
}) })
} else { if err != nil {
var thresholdsJSON = []byte{} this.ErrorPage(err)
var thresholds = address.GetSlice("thresholds") return
if len(thresholds) > 0 {
thresholdsJSON, _ = json.Marshal(thresholds)
} }
} else {
_, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{ createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
NodeId: nodeId, NodeId: nodeId,
Role: nodeconfigs.NodeRoleNode, Role: nodeconfigs.NodeRoleNode,
Name: address.GetString("name"), Name: addr.GetString("name"),
Ip: address.GetString("ip"), Ip: addr.GetString("ip"),
CanAccess: address.GetBool("canAccess"), CanAccess: addr.GetBool("canAccess"),
ThresholdsJSON: thresholdsJSON, IsUp: addr.GetBool("isUp"),
}) })
if err != nil {
this.ErrorPage(err)
return
}
addrId = createResp.NodeIPAddressId
} }
if err != nil {
this.ErrorPage(err) // 阈值
return var thresholds = addr.GetSlice("thresholds")
if len(thresholds) > 0 {
thresholdsJSON, err := json.Marshal(thresholds)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(this.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
NodeIPAddressId: addrId,
NodeIPAddressThresholdsJSON: thresholdsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
} }
} }

View File

@@ -4,7 +4,11 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders" "github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/groups" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/groups"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/thresholds" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/cache"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/dns"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/ssh"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/system"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/thresholds"
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils" clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo" "github.com/iwind/TeaGo"
@@ -42,10 +46,14 @@ func init() {
Post("/start", new(node.StartAction)). Post("/start", new(node.StartAction)).
Post("/stop", new(node.StopAction)). Post("/stop", new(node.StopAction)).
Post("/up", new(node.UpAction)). Post("/up", new(node.UpAction)).
Get("/thresholds", new(thresholds.IndexAction)).
Get("/detail", new(node.DetailAction)). Get("/detail", new(node.DetailAction)).
GetPost("/updateDNSPopup", new(node.UpdateDNSPopupAction)). GetPost("/updateDNSPopup", new(node.UpdateDNSPopupAction)).
Post("/syncDomain", new(node.SyncDomainAction)). Post("/syncDomain", new(node.SyncDomainAction)).
GetPost("/settings/cache", new(cache.IndexAction)).
GetPost("/settings/dns", new(dns.IndexAction)).
GetPost("/settings/system", new(system.IndexAction)).
GetPost("/settings/ssh", new(ssh.IndexAction)).
GetPost("/settings/thresholds", new(thresholds.IndexAction)).
// 分组相关 // 分组相关
Prefix("/clusters/cluster/groups"). Prefix("/clusters/cluster/groups").

View File

@@ -7,6 +7,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils" "github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
@@ -68,7 +69,7 @@ func (this *DetailAction) RunGet(params struct {
} }
// IP地址 // IP地址
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{ ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
Role: nodeconfigs.NodeRoleNode, Role: nodeconfigs.NodeRoleNode,
}) })
@@ -76,17 +77,15 @@ func (this *DetailAction) RunGet(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
var ipAddresses = ipAddressesResp.Addresses var ipAddresses = ipAddressesResp.NodeIPAddresses
ipAddressMaps := []maps.Map{} ipAddressMaps := []maps.Map{}
for _, addr := range ipAddressesResp.Addresses { for _, addr := range ipAddressesResp.NodeIPAddresses {
var thresholds = []*nodeconfigs.NodeValueThresholdConfig{} thresholds, err := ipaddressutils.InitNodeIPAddressThresholds(this.Parent(), addr.Id)
if len(addr.ThresholdsJSON) > 0 { if err != nil {
err = json.Unmarshal(addr.ThresholdsJSON, &thresholds) this.ErrorPage(err)
if err != nil { return
this.ErrorPage(err)
return
}
} }
ipAddressMaps = append(ipAddressMaps, maps.Map{ ipAddressMaps = append(ipAddressMaps, maps.Map{
"id": addr.Id, "id": addr.Id,
"name": addr.Name, "name": addr.Name,

View File

@@ -20,7 +20,7 @@ func (this *IndexAction) Init() {
func (this *IndexAction) RunGet(params struct { func (this *IndexAction) RunGet(params struct {
NodeId int64 NodeId int64
}) { }) {
err := nodeutils.InitNodeInfo(this, params.NodeId) _, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return

View File

@@ -3,6 +3,7 @@ package node
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs" "github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
@@ -25,16 +26,11 @@ func (this *InstallAction) RunGet(params struct {
this.Data["nodeId"] = params.NodeId this.Data["nodeId"] = params.NodeId
// 节点 // 节点
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId}) node, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
node := nodeResp.Node
if node == nil {
this.WriteString("找不到要操作的节点")
return
}
// 安装信息 // 安装信息
if node.InstallStatus != nil { if node.InstallStatus != nil {
@@ -84,15 +80,12 @@ func (this *InstallAction) RunGet(params struct {
} }
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\"" this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
this.Data["node"] = maps.Map{ var nodeMap = this.Data["node"].(maps.Map)
"id": node.Id, nodeMap["installDir"] = node.InstallDir
"name": node.Name, nodeMap["isInstalled"] = node.IsInstalled
"installDir": node.InstallDir, nodeMap["uniqueId"] = node.UniqueId
"isInstalled": node.IsInstalled, nodeMap["secret"] = node.Secret
"uniqueId": node.UniqueId, nodeMap["cluster"] = clusterMap
"secret": node.Secret,
"cluster": clusterMap,
}
this.Show() this.Show()
} }

View File

@@ -25,7 +25,7 @@ func (this *LogsAction) RunGet(params struct {
Level string Level string
}) { }) {
// 初始化节点信息(用于菜单) // 初始化节点信息(用于菜单)
err := nodeutils.InitNodeInfo(this, params.NodeId) _, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return

View File

@@ -7,28 +7,80 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"strconv" "strconv"
) )
// InitNodeInfo 初始化节点信息 // InitNodeInfo 初始化节点信息
func InitNodeInfo(action actionutils.ActionInterface, nodeId int64) error { func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Node, error) {
// 节点信息(用于菜单) // 节点信息(用于菜单)
nodeResp, err := action.RPC().NodeRPC().FindEnabledNode(action.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: nodeId}) nodeResp, err := parentAction.RPC().NodeRPC().FindEnabledNode(parentAction.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: nodeId})
if err != nil { if err != nil {
return err return nil, err
} }
if nodeResp.Node == nil { if nodeResp.Node == nil {
return errors.New("node '" + strconv.FormatInt(nodeId, 10) + "' not found") return nil, errors.New("node '" + strconv.FormatInt(nodeId, 10) + "' not found")
} }
var node = nodeResp.Node var node = nodeResp.Node
action.ViewData()["node"] = maps.Map{
"id": node.Id, var groupMap maps.Map
"name": node.Name, if node.NodeGroup != nil {
"isOn": node.IsOn, groupMap = maps.Map{
"isUp": node.IsUp, "id": node.NodeGroup.Id,
"name": node.NodeGroup.Name,
}
} }
parentAction.Data["node"] = maps.Map{
"id": node.Id,
"name": node.Name,
"isOn": node.IsOn,
"isUp": node.IsUp,
"group": groupMap,
}
var clusterId int64 = 0
if node.NodeCluster != nil { if node.NodeCluster != nil {
action.ViewData()["clusterId"] = node.NodeCluster.Id parentAction.Data["clusterId"] = node.NodeCluster.Id
clusterId = node.NodeCluster.Id
} }
return nil
// 左侧菜单
var prefix = "/clusters/cluster/node"
var query = "clusterId=" + types.String(clusterId) + "&nodeId=" + types.String(nodeId)
var menuItem = parentAction.Data.GetString("secondMenuItem")
parentAction.Data["leftMenuItems"] = []maps.Map{
{
"name": "基础设置",
"url": prefix + "/update?" + query,
"isActive": menuItem == "basic",
},
{
"name": "DNS设置",
"url": prefix + "/settings/dns?" + query,
"isActive": menuItem == "dns",
},
{
"name": "缓存设置",
"url": prefix + "/settings/cache?" + query,
"isActive": menuItem == "cache",
},
{
"name": "阈值设置",
"url": prefix + "/settings/thresholds?" + query,
"isActive": menuItem == "threshold",
},
{
"name": "SSH设置",
"url": prefix + "/settings/ssh?" + query,
"isActive": menuItem == "ssh",
},
{
"name": "系统设置",
"url": prefix + "/settings/system?" + query,
"isActive": menuItem == "system",
},
}
return nodeResp.Node, nil
} }

View File

@@ -0,0 +1,117 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package cache
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "update")
this.SecondMenu("cache")
}
func (this *IndexAction) RunGet(params struct {
NodeId int64
}) {
node, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
if err != nil {
this.ErrorPage(err)
return
}
// 缓存硬盘 & 内存容量
var maxCacheDiskCapacity maps.Map = nil
if node.MaxCacheDiskCapacity != nil {
maxCacheDiskCapacity = maps.Map{
"count": node.MaxCacheDiskCapacity.Count,
"unit": node.MaxCacheDiskCapacity.Unit,
}
} else {
maxCacheDiskCapacity = maps.Map{
"count": 0,
"unit": "gb",
}
}
var maxCacheMemoryCapacity maps.Map = nil
if node.MaxCacheMemoryCapacity != nil {
maxCacheMemoryCapacity = maps.Map{
"count": node.MaxCacheMemoryCapacity.Count,
"unit": node.MaxCacheMemoryCapacity.Unit,
}
} else {
maxCacheMemoryCapacity = maps.Map{
"count": 0,
"unit": "gb",
}
}
var nodeMap = this.Data["node"].(maps.Map)
nodeMap["maxCacheDiskCapacity"] = maxCacheDiskCapacity
nodeMap["maxCacheMemoryCapacity"] = maxCacheMemoryCapacity
this.Show()
}
func (this *IndexAction) RunPost(params struct {
NodeId int64
MaxCacheDiskCapacityJSON []byte
MaxCacheMemoryCapacityJSON []byte
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改节点 %d 缓存设置", params.NodeId)
// 缓存硬盘 & 内存容量
var pbMaxCacheDiskCapacity *pb.SizeCapacity
if len(params.MaxCacheDiskCapacityJSON) > 0 {
var sizeCapacity = &shared.SizeCapacity{}
err := json.Unmarshal(params.MaxCacheDiskCapacityJSON, sizeCapacity)
if err != nil {
this.ErrorPage(err)
return
}
pbMaxCacheDiskCapacity = &pb.SizeCapacity{
Count: sizeCapacity.Count,
Unit: sizeCapacity.Unit,
}
}
var pbMaxCacheMemoryCapacity *pb.SizeCapacity
if len(params.MaxCacheMemoryCapacityJSON) > 0 {
var sizeCapacity = &shared.SizeCapacity{}
err := json.Unmarshal(params.MaxCacheMemoryCapacityJSON, sizeCapacity)
if err != nil {
this.ErrorPage(err)
return
}
pbMaxCacheMemoryCapacity = &pb.SizeCapacity{
Count: sizeCapacity.Count,
Unit: sizeCapacity.Unit,
}
}
_, err := this.RPC().NodeRPC().UpdateNodeCache(this.AdminContext(), &pb.UpdateNodeCacheRequest{
NodeId: params.NodeId,
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,125 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dns
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "update")
this.SecondMenu("dns")
}
func (this *IndexAction) RunGet(params struct {
NodeId int64
}) {
node, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
if err != nil {
this.ErrorPage(err)
return
}
// DNS相关
var clusters = []*pb.NodeCluster{node.NodeCluster}
clusters = append(clusters, node.SecondaryNodeClusters...)
var allDNSRouteMaps = map[int64][]maps.Map{} // domain id => routes
var routeMaps = map[int64][]maps.Map{} // domain id => routes
for _, cluster := range clusters {
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
NodeId: params.NodeId,
NodeClusterId: cluster.Id,
})
if err != nil {
this.ErrorPage(err)
return
}
var dnsInfo = dnsInfoResp.Node
if dnsInfo.DnsDomainId <= 0 || len(dnsInfo.DnsDomainName) == 0 {
continue
}
var domainId = dnsInfo.DnsDomainId
var domainName = dnsInfo.DnsDomainName
if len(dnsInfo.Routes) > 0 {
for _, route := range dnsInfo.Routes {
routeMaps[domainId] = append(routeMaps[domainId], maps.Map{
"domainId": domainId,
"domainName": domainName,
"code": route.Code,
"name": route.Name,
})
}
}
// 所有线路选项
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: dnsInfoResp.Node.DnsDomainId})
if err != nil {
this.ErrorPage(err)
return
}
for _, route := range routesResp.Routes {
allDNSRouteMaps[domainId] = append(allDNSRouteMaps[domainId], maps.Map{
"domainId": domainId,
"domainName": domainName,
"name": route.Name,
"code": route.Code,
})
}
}
var domainRoutes = []maps.Map{}
for _, m := range routeMaps {
domainRoutes = append(domainRoutes, m...)
}
this.Data["dnsRoutes"] = domainRoutes
var allDomainRoutes = []maps.Map{}
for _, m := range allDNSRouteMaps {
allDomainRoutes = append(allDomainRoutes, m...)
}
this.Data["allDNSRoutes"] = allDomainRoutes
this.Show()
}
func (this *IndexAction) RunPost(params struct {
NodeId int64
DnsDomainId int64
DnsRoutesJSON []byte
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改节点 %d DNS设置", params.NodeId)
dnsRouteCodes := []string{}
if len(params.DnsRoutesJSON) > 0 {
err := json.Unmarshal(params.DnsRoutesJSON, &dnsRouteCodes)
if err != nil {
this.ErrorPage(err)
return
}
}
_, err := this.RPC().NodeRPC().UpdateNodeDNS(this.AdminContext(), &pb.UpdateNodeDNSRequest{
NodeId: params.NodeId,
IpAddr: "",
DnsDomainId: 0,
Routes: dnsRouteCodes,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,114 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ssh
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "update")
this.SecondMenu("ssh")
}
func (this *IndexAction) RunGet(params struct {
NodeId int64
}) {
node, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
if err != nil {
this.ErrorPage(err)
return
}
// 登录信息
var loginMap maps.Map = nil
if node.NodeLogin != nil {
loginParams := maps.Map{}
if len(node.NodeLogin.Params) > 0 {
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
if err != nil {
this.ErrorPage(err)
return
}
}
grantMap := maps.Map{}
grantId := loginParams.GetInt64("grantId")
if grantId > 0 {
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
if err != nil {
this.ErrorPage(err)
return
}
if grantResp.NodeGrant != nil {
grantMap = maps.Map{
"id": grantResp.NodeGrant.Id,
"name": grantResp.NodeGrant.Name,
"method": grantResp.NodeGrant.Method,
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
"username": grantResp.NodeGrant.Username,
}
}
}
loginMap = maps.Map{
"id": node.NodeLogin.Id,
"name": node.NodeLogin.Name,
"type": node.NodeLogin.Type,
"params": loginParams,
"grant": grantMap,
}
}
var nodeMap = this.Data["node"].(maps.Map)
nodeMap["login"] = loginMap
this.Show()
}
func (this *IndexAction) RunPost(params struct {
NodeId int64
LoginId int64
GrantId int64
SshHost string
SshPort int
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改节点 %d SSH登录信息", params.NodeId)
// TODO 检查登录授权
loginInfo := &pb.NodeLogin{
Id: params.LoginId,
Name: "SSH",
Type: "ssh",
Params: maps.Map{
"grantId": params.GrantId,
"host": params.SshHost,
"port": params.SshPort,
}.AsJSON(),
}
_, err := this.RPC().NodeRPC().UpdateNodeLogin(this.AdminContext(), &pb.UpdateNodeLoginRequest{
NodeId: params.NodeId,
NodeLogin: loginInfo,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,61 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package system
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "update")
this.SecondMenu("system")
}
func (this *IndexAction) RunGet(params struct {
NodeId int64
}) {
node, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
if err != nil {
this.ErrorPage(err)
return
}
// 获取节点信息
var nodeMap = this.Data["node"].(maps.Map)
nodeMap["maxCPU"] = node.MaxCPU
this.Show()
}
func (this *IndexAction) RunPost(params struct {
NodeId int64
MaxCPU int32
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改节点 %d 系统信息", params.NodeId)
if params.MaxCPU < 0 {
this.Fail("CPU线程数不能小于0")
}
_, err := this.RPC().NodeRPC().UpdateNodeSystem(this.AdminContext(), &pb.UpdateNodeSystemRequest{
NodeId: params.NodeId,
MaxCPU: params.MaxCPU,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -15,22 +15,22 @@ type IndexAction struct {
} }
func (this *IndexAction) Init() { func (this *IndexAction) Init() {
this.Nav("", "node", "threshold") this.Nav("", "", "update")
this.SecondMenu("threshold")
} }
func (this *IndexAction) RunGet(params struct { func (this *IndexAction) RunGet(params struct {
ClusterId int64 ClusterId int64
NodeId int64 NodeId int64
}) { }) {
this.Data["nodeId"] = params.NodeId _, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
// 初始化节点信息(用于菜单)
err := nodeutils.InitNodeInfo(this, params.NodeId)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
this.Data["nodeId"] = params.NodeId
// 列出所有阈值 // 列出所有阈值
thresholdsResp, err := this.RPC().NodeThresholdRPC().FindAllEnabledNodeThresholds(this.AdminContext(), &pb.FindAllEnabledNodeThresholdsRequest{ thresholdsResp, err := this.RPC().NodeThresholdRPC().FindAllEnabledNodeThresholds(this.AdminContext(), &pb.FindAllEnabledNodeThresholdsRequest{
Role: "node", Role: "node",

View File

@@ -6,7 +6,7 @@ import (
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
) )
// 节点状态 // StatusAction 节点状态
type StatusAction struct { type StatusAction struct {
actionutils.ParentAction actionutils.ParentAction
} }

View File

@@ -4,11 +4,10 @@ import (
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs" "github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
) )
@@ -19,12 +18,18 @@ type UpdateAction struct {
func (this *UpdateAction) Init() { func (this *UpdateAction) Init() {
this.Nav("", "node", "update") this.Nav("", "node", "update")
this.SecondMenu("nodes") this.SecondMenu("basic")
} }
func (this *UpdateAction) RunGet(params struct { func (this *UpdateAction) RunGet(params struct {
NodeId int64 NodeId int64
}) { }) {
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["nodeId"] = params.NodeId this.Data["nodeId"] = params.NodeId
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId}) nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId})
@@ -47,7 +52,7 @@ func (this *UpdateAction) RunGet(params struct {
} }
// IP地址 // IP地址
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{ ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
Role: nodeconfigs.NodeRoleNode, Role: nodeconfigs.NodeRoleNode,
}) })
@@ -56,14 +61,11 @@ func (this *UpdateAction) RunGet(params struct {
return return
} }
ipAddressMaps := []maps.Map{} ipAddressMaps := []maps.Map{}
for _, addr := range ipAddressesResp.Addresses { for _, addr := range ipAddressesResp.NodeIPAddresses {
var thresholds = []*nodeconfigs.NodeValueThresholdConfig{} thresholds, err := ipaddressutils.InitNodeIPAddressThresholds(this.Parent(), addr.Id)
if len(addr.ThresholdsJSON) > 0 { if err != nil {
err = json.Unmarshal(addr.ThresholdsJSON, &thresholds) this.ErrorPage(err)
if err != nil { return
this.ErrorPage(err)
return
}
} }
ipAddressMaps = append(ipAddressMaps, maps.Map{ ipAddressMaps = append(ipAddressMaps, maps.Map{
@@ -77,105 +79,6 @@ func (this *UpdateAction) RunGet(params struct {
}) })
} }
// DNS相关
var clusters = []*pb.NodeCluster{node.NodeCluster}
clusters = append(clusters, node.SecondaryNodeClusters...)
var allDNSRouteMaps = map[int64][]maps.Map{} // domain id => routes
var routeMaps = map[int64][]maps.Map{} // domain id => routes
for _, cluster := range clusters {
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
NodeId: params.NodeId,
NodeClusterId: cluster.Id,
})
if err != nil {
this.ErrorPage(err)
return
}
var dnsInfo = dnsInfoResp.Node
if dnsInfo.DnsDomainId <= 0 || len(dnsInfo.DnsDomainName) == 0 {
continue
}
var domainId = dnsInfo.DnsDomainId
var domainName = dnsInfo.DnsDomainName
if len(dnsInfo.Routes) > 0 {
for _, route := range dnsInfo.Routes {
routeMaps[domainId] = append(routeMaps[domainId], maps.Map{
"domainId": domainId,
"domainName": domainName,
"code": route.Code,
"name": route.Name,
})
}
}
// 所有线路选项
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: dnsInfoResp.Node.DnsDomainId})
if err != nil {
this.ErrorPage(err)
return
}
for _, route := range routesResp.Routes {
allDNSRouteMaps[domainId] = append(allDNSRouteMaps[domainId], maps.Map{
"domainId": domainId,
"domainName": domainName,
"name": route.Name,
"code": route.Code,
})
}
}
var domainRoutes = []maps.Map{}
for _, m := range routeMaps {
domainRoutes = append(domainRoutes, m...)
}
this.Data["dnsRoutes"] = domainRoutes
var allDomainRoutes = []maps.Map{}
for _, m := range allDNSRouteMaps {
allDomainRoutes = append(allDomainRoutes, m...)
}
this.Data["allDNSRoutes"] = allDomainRoutes
// 登录信息
var loginMap maps.Map = nil
if node.NodeLogin != nil {
loginParams := maps.Map{}
if len(node.NodeLogin.Params) > 0 {
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
if err != nil {
this.ErrorPage(err)
return
}
}
grantMap := maps.Map{}
grantId := loginParams.GetInt64("grantId")
if grantId > 0 {
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
if err != nil {
this.ErrorPage(err)
return
}
if grantResp.NodeGrant != nil {
grantMap = maps.Map{
"id": grantResp.NodeGrant.Id,
"name": grantResp.NodeGrant.Name,
"method": grantResp.NodeGrant.Method,
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
"username": grantResp.NodeGrant.Username,
}
}
}
loginMap = maps.Map{
"id": node.NodeLogin.Id,
"name": node.NodeLogin.Name,
"type": node.NodeLogin.Type,
"params": loginParams,
"grant": grantMap,
}
}
// 分组 // 分组
var groupMap maps.Map = nil var groupMap maps.Map = nil
if node.NodeGroup != nil { if node.NodeGroup != nil {
@@ -194,45 +97,14 @@ func (this *UpdateAction) RunGet(params struct {
} }
} }
// 缓存硬盘 & 内存容量
var maxCacheDiskCapacity maps.Map = nil
if node.MaxCacheDiskCapacity != nil {
maxCacheDiskCapacity = maps.Map{
"count": node.MaxCacheDiskCapacity.Count,
"unit": node.MaxCacheDiskCapacity.Unit,
}
} else {
maxCacheDiskCapacity = maps.Map{
"count": 0,
"unit": "gb",
}
}
var maxCacheMemoryCapacity maps.Map = nil
if node.MaxCacheMemoryCapacity != nil {
maxCacheMemoryCapacity = maps.Map{
"count": node.MaxCacheMemoryCapacity.Count,
"unit": node.MaxCacheMemoryCapacity.Unit,
}
} else {
maxCacheMemoryCapacity = maps.Map{
"count": 0,
"unit": "gb",
}
}
var m = maps.Map{ var m = maps.Map{
"id": node.Id, "id": node.Id,
"name": node.Name, "name": node.Name,
"ipAddresses": ipAddressMaps, "ipAddresses": ipAddressMaps,
"cluster": clusterMap, "cluster": clusterMap,
"login": loginMap, "isOn": node.IsOn,
"maxCPU": node.MaxCPU, "group": groupMap,
"isOn": node.IsOn, "region": regionMap,
"group": groupMap,
"region": regionMap,
"maxCacheDiskCapacity": maxCacheDiskCapacity,
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
} }
if node.NodeCluster != nil { if node.NodeCluster != nil {
@@ -263,24 +135,15 @@ func (this *UpdateAction) RunGet(params struct {
} }
func (this *UpdateAction) RunPost(params struct { func (this *UpdateAction) RunPost(params struct {
LoginId int64 LoginId int64
NodeId int64 NodeId int64
GroupId int64 GroupId int64
RegionId int64 RegionId int64
Name string Name string
IPAddressesJSON []byte `alias:"ipAddressesJSON"` IPAddressesJSON []byte `alias:"ipAddressesJSON"`
PrimaryClusterId int64 PrimaryClusterId int64
SecondaryClusterIds []byte SecondaryClusterIds []byte
GrantId int64 IsOn bool
SshHost string
SshPort int
MaxCPU int32
IsOn bool
MaxCacheDiskCapacityJSON []byte
MaxCacheMemoryCapacityJSON []byte
DnsDomainId int64
DnsRoutesJSON []byte
Must *actions.Must Must *actions.Must
}) { }) {
@@ -322,56 +185,6 @@ func (this *UpdateAction) RunPost(params struct {
this.Fail("请至少输入一个IP地址") this.Fail("请至少输入一个IP地址")
} }
dnsRouteCodes := []string{}
if len(params.DnsRoutesJSON) > 0 {
err := json.Unmarshal(params.DnsRoutesJSON, &dnsRouteCodes)
if err != nil {
this.ErrorPage(err)
return
}
}
// TODO 检查登录授权
loginInfo := &pb.NodeLogin{
Id: params.LoginId,
Name: "SSH",
Type: "ssh",
Params: maps.Map{
"grantId": params.GrantId,
"host": params.SshHost,
"port": params.SshPort,
}.AsJSON(),
}
// 缓存硬盘 & 内存容量
var pbMaxCacheDiskCapacity *pb.SizeCapacity
if len(params.MaxCacheDiskCapacityJSON) > 0 {
var sizeCapacity = &shared.SizeCapacity{}
err := json.Unmarshal(params.MaxCacheDiskCapacityJSON, sizeCapacity)
if err != nil {
this.ErrorPage(err)
return
}
pbMaxCacheDiskCapacity = &pb.SizeCapacity{
Count: sizeCapacity.Count,
Unit: sizeCapacity.Unit,
}
}
var pbMaxCacheMemoryCapacity *pb.SizeCapacity
if len(params.MaxCacheMemoryCapacityJSON) > 0 {
var sizeCapacity = &shared.SizeCapacity{}
err := json.Unmarshal(params.MaxCacheMemoryCapacityJSON, sizeCapacity)
if err != nil {
this.ErrorPage(err)
return
}
pbMaxCacheMemoryCapacity = &pb.SizeCapacity{
Count: sizeCapacity.Count,
Unit: sizeCapacity.Unit,
}
}
// 保存 // 保存
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{ _, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
@@ -380,13 +193,7 @@ func (this *UpdateAction) RunPost(params struct {
Name: params.Name, Name: params.Name,
NodeClusterId: params.PrimaryClusterId, NodeClusterId: params.PrimaryClusterId,
SecondaryNodeClusterIds: secondaryClusterIds, SecondaryNodeClusterIds: secondaryClusterIds,
NodeLogin: loginInfo,
MaxCPU: params.MaxCPU,
IsOn: params.IsOn, IsOn: params.IsOn,
DnsDomainId: params.DnsDomainId,
DnsRoutes: dnsRouteCodes,
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -394,7 +201,7 @@ func (this *UpdateAction) RunPost(params struct {
} }
// 禁用老的IP地址 // 禁用老的IP地址
_, err = this.RPC().NodeIPAddressRPC().DisableAllIPAddressesWithNodeId(this.AdminContext(), &pb.DisableAllIPAddressesWithNodeIdRequest{ _, err = this.RPC().NodeIPAddressRPC().DisableAllNodeIPAddressesWithNodeId(this.AdminContext(), &pb.DisableAllNodeIPAddressesWithNodeIdRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
Role: nodeconfigs.NodeRoleNode, Role: nodeconfigs.NodeRoleNode,
}) })

View File

@@ -85,10 +85,12 @@ func (this *UpdateDNSPopupAction) RunPost(params struct {
defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d 的DNS设置", params.NodeId) defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d 的DNS设置", params.NodeId)
routes := []string{} routes := []string{}
err := json.Unmarshal(params.DnsRoutesJSON, &routes) if len(params.DnsRoutesJSON) > 0 {
if err != nil { err := json.Unmarshal(params.DnsRoutesJSON, &routes)
this.ErrorPage(err) if err != nil {
return this.ErrorPage(err)
return
}
} }
params.Must. params.Must.
@@ -100,7 +102,7 @@ func (this *UpdateDNSPopupAction) RunPost(params struct {
} }
// 执行修改 // 执行修改
_, err = this.RPC().NodeRPC().UpdateNodeDNS(this.AdminContext(), &pb.UpdateNodeDNSRequest{ _, err := this.RPC().NodeRPC().UpdateNodeDNS(this.AdminContext(), &pb.UpdateNodeDNSRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
IpAddr: params.IpAddr, IpAddr: params.IpAddr,
DnsDomainId: params.DomainId, DnsDomainId: params.DomainId,

View File

@@ -123,7 +123,7 @@ func (this *NodesAction) RunGet(params struct {
} }
// IP // IP
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{ ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
NodeId: node.Id, NodeId: node.Id,
Role: nodeconfigs.NodeRoleNode, Role: nodeconfigs.NodeRoleNode,
}) })
@@ -132,7 +132,7 @@ func (this *NodesAction) RunGet(params struct {
return return
} }
ipAddresses := []maps.Map{} ipAddresses := []maps.Map{}
for _, addr := range ipAddressesResp.Addresses { for _, addr := range ipAddressesResp.NodeIPAddresses {
ipAddresses = append(ipAddresses, maps.Map{ ipAddresses = append(ipAddresses, maps.Map{
"id": addr.Id, "id": addr.Id,
"name": addr.Name, "name": addr.Name,

View File

@@ -46,6 +46,13 @@ func (this *IndexAction) RunGet(params struct {
this.Data["domainName"] = dnsInfoResp.Domain.Name this.Data["domainName"] = dnsInfoResp.Domain.Name
} }
if len(dnsInfoResp.CnameRecords) == 0 {
this.Data["cnameRecords"] = []string{}
} else {
this.Data["cnameRecords"] = dnsInfoResp.CnameRecords
}
this.Data["ttl"] = dnsInfoResp.Ttl
this.Show() this.Show()
} }
@@ -56,6 +63,8 @@ func (this *IndexAction) RunPost(params struct {
DnsName string DnsName string
NodesAutoSync bool NodesAutoSync bool
ServersAutoSync bool ServersAutoSync bool
CnameRecords []string
Ttl int32
Must *actions.Must Must *actions.Must
CSRF *actionutils.CSRF CSRF *actionutils.CSRF
@@ -97,6 +106,8 @@ func (this *IndexAction) RunPost(params struct {
DnsDomainId: params.DnsDomainId, DnsDomainId: params.DnsDomainId,
NodesAutoSync: params.NodesAutoSync, NodesAutoSync: params.NodesAutoSync,
ServersAutoSync: params.ServersAutoSync, ServersAutoSync: params.ServersAutoSync,
CnameRecords: params.CnameRecords,
Ttl: params.Ttl,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -45,6 +45,7 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
action.WriteString("can not find cluster") action.WriteString("can not find cluster")
return return
} }
action.Data["currentClusterName"] = cluster.Name
clusterInfo, err := dao.SharedNodeClusterDAO.FindEnabledNodeClusterConfigInfo(ctx, clusterId) clusterInfo, err := dao.SharedNodeClusterDAO.FindEnabledNodeClusterConfigInfo(ctx, clusterId)
if err != nil { if err != nil {

View File

@@ -193,7 +193,7 @@ func (this *IndexAction) searchNodes(keyword string) {
} }
// IP // IP
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{ ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
NodeId: node.Id, NodeId: node.Id,
Role: nodeconfigs.NodeRoleNode, Role: nodeconfigs.NodeRoleNode,
}) })
@@ -202,7 +202,7 @@ func (this *IndexAction) searchNodes(keyword string) {
return return
} }
ipAddresses := []maps.Map{} ipAddresses := []maps.Map{}
for _, addr := range ipAddressesResp.Addresses { for _, addr := range ipAddressesResp.NodeIPAddresses {
ipAddresses = append(ipAddresses, maps.Map{ ipAddresses = append(ipAddresses, maps.Map{
"id": addr.Id, "id": addr.Id,
"name": addr.Name, "name": addr.Name,

View File

@@ -0,0 +1,32 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package groups
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type OptionsAction struct {
actionutils.ParentAction
}
func (this *OptionsAction) RunPost(params struct{}) {
resp, err := this.RPC().ReportNodeGroupRPC().FindAllEnabledReportNodeGroups(this.AdminContext(), &pb.FindAllEnabledReportNodeGroupsRequest{})
if err != nil {
this.ErrorPage(err)
return
}
var groupMaps = []maps.Map{}
for _, group := range resp.ReportNodeGroups {
groupMaps = append(groupMaps, maps.Map{
"id": group.Id,
"name": group.Name,
})
}
this.Data["groups"] = groupMaps
this.Success()
}

View File

@@ -40,6 +40,10 @@ func (this *IndexAction) RunGet(params struct{}) {
} }
} }
this.Show()
}
func (this *IndexAction) RunPost(params struct{}) {
// 读取看板数据 // 读取看板数据
resp, err := this.RPC().AdminRPC().ComposeAdminDashboard(this.AdminContext(), &pb.ComposeAdminDashboardRequest{ resp, err := this.RPC().AdminRPC().ComposeAdminDashboard(this.AdminContext(), &pb.ComposeAdminDashboardRequest{
ApiVersion: teaconst.APINodeVersion, ApiVersion: teaconst.APINodeVersion,
@@ -50,7 +54,7 @@ func (this *IndexAction) RunGet(params struct{}) {
} }
this.Data["dashboard"] = maps.Map{ this.Data["dashboard"] = maps.Map{
"defaultClusterId": resp.DefaultNodeClusterId, "defaultClusterId": resp.DefaultNodeClusterId,
"countServers": resp.CountServers, "countServers": resp.CountServers,
"countNodeClusters": resp.CountNodeClusters, "countNodeClusters": resp.CountNodeClusters,
"countNodes": resp.CountNodes, "countNodes": resp.CountNodes,
@@ -85,8 +89,14 @@ func (this *IndexAction) RunGet(params struct{}) {
statMaps := []maps.Map{} statMaps := []maps.Map{}
for _, stat := range resp.HourlyTrafficStats { for _, stat := range resp.HourlyTrafficStats {
statMaps = append(statMaps, maps.Map{ statMaps = append(statMaps, maps.Map{
"bytes": stat.Bytes, "bytes": stat.Bytes,
"hour": stat.Hour[8:], "cachedBytes": stat.CachedBytes,
"countRequests": stat.CountRequests,
"countCachedRequests": stat.CountCachedRequests,
"countAttackRequests": stat.CountAttackRequests,
"attackBytes": stat.AttackBytes,
"day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
"hour": stat.Hour[8:],
}) })
} }
this.Data["hourlyTrafficStats"] = statMaps this.Data["hourlyTrafficStats"] = statMaps
@@ -97,8 +107,13 @@ func (this *IndexAction) RunGet(params struct{}) {
statMaps := []maps.Map{} statMaps := []maps.Map{}
for _, stat := range resp.DailyTrafficStats { for _, stat := range resp.DailyTrafficStats {
statMaps = append(statMaps, maps.Map{ statMaps = append(statMaps, maps.Map{
"bytes": stat.Bytes, "bytes": stat.Bytes,
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日", "cachedBytes": stat.CachedBytes,
"countRequests": stat.CountRequests,
"countCachedRequests": stat.CountCachedRequests,
"countAttackRequests": stat.CountAttackRequests,
"attackBytes": stat.AttackBytes,
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
}) })
} }
this.Data["dailyTrafficStats"] = statMaps this.Data["dailyTrafficStats"] = statMaps
@@ -172,6 +187,20 @@ func (this *IndexAction) RunGet(params struct{}) {
} }
} }
// 域名排行
{
var statMaps = []maps.Map{}
for _, stat := range resp.TopDomainStats {
statMaps = append(statMaps, maps.Map{
"serverId": stat.ServerId,
"domain": stat.Domain,
"countRequests": stat.CountRequests,
"bytes": stat.Bytes,
})
}
this.Data["topDomainStats"] = statMaps
}
// 指标 // 指标
{ {
var chartMaps = []maps.Map{} var chartMaps = []maps.Map{}
@@ -210,5 +239,5 @@ func (this *IndexAction) RunGet(params struct{}) {
this.Data["metricCharts"] = chartMaps this.Data["metricCharts"] = chartMaps
} }
this.Show() this.Success()
} }

View File

@@ -5,6 +5,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
) )
type ClusterAction struct { type ClusterAction struct {
@@ -61,6 +62,12 @@ func (this *ClusterAction) RunGet(params struct {
dnsMap["providerTypeName"] = dnsResp.Provider.TypeName dnsMap["providerTypeName"] = dnsResp.Provider.TypeName
} }
if len(dnsResp.CnameRecords) > 0 {
dnsMap["cnameRecords"] = dnsResp.CnameRecords
} else {
dnsMap["cnameRecords"] = []string{}
}
this.Data["dnsInfo"] = dnsMap this.Data["dnsInfo"] = dnsMap
// 节点DNS解析记录 // 节点DNS解析记录
@@ -203,5 +210,60 @@ func (this *ClusterAction) RunGet(params struct {
} }
this.Data["issues"] = issueMaps this.Data["issues"] = issueMaps
// 当前正在执行的任务
resp, err := this.RPC().DNSTaskRPC().FindAllDoingDNSTasks(this.AdminContext(), &pb.FindAllDoingDNSTasksRequest{
NodeClusterId: params.ClusterId,
})
if err != nil {
this.ErrorPage(err)
return
}
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() this.Show()
} }

View File

@@ -85,10 +85,12 @@ func (this *UpdateNodePopupAction) RunPost(params struct {
defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d 的DNS设置", params.NodeId) defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d 的DNS设置", params.NodeId)
routes := []string{} routes := []string{}
err := json.Unmarshal(params.DnsRoutesJSON, &routes) if len(params.DnsRoutesJSON) > 0 {
if err != nil { err := json.Unmarshal(params.DnsRoutesJSON, &routes)
this.ErrorPage(err) if err != nil {
return this.ErrorPage(err)
return
}
} }
params.Must. params.Must.
@@ -100,7 +102,7 @@ func (this *UpdateNodePopupAction) RunPost(params struct {
} }
// 执行修改 // 执行修改
_, err = this.RPC().NodeRPC().UpdateNodeDNS(this.AdminContext(), &pb.UpdateNodeDNSRequest{ _, err := this.RPC().NodeRPC().UpdateNodeDNS(this.AdminContext(), &pb.UpdateNodeDNSRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
IpAddr: params.IpAddr, IpAddr: params.IpAddr,
DnsDomainId: params.DomainId, DnsDomainId: params.DomainId,

View File

@@ -9,7 +9,7 @@ import (
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
) )
// 修改集群的DNS设置 // UpdateClusterPopupAction 修改集群的DNS设置
type UpdateClusterPopupAction struct { type UpdateClusterPopupAction struct {
actionutils.ParentAction actionutils.ParentAction
} }
@@ -46,6 +46,14 @@ func (this *UpdateClusterPopupAction) RunGet(params struct {
this.Data["providerId"] = 0 this.Data["providerId"] = 0
} }
if len(dnsResp.CnameRecords) == 0 {
this.Data["cnameRecords"] = []string{}
} else {
this.Data["cnameRecords"] = dnsResp.CnameRecords
}
this.Data["ttl"] = dnsResp.Ttl
// 所有服务商 // 所有服务商
providerTypesResp, err := this.RPC().DNSProviderRPC().FindAllDNSProviderTypes(this.AdminContext(), &pb.FindAllDNSProviderTypesRequest{}) providerTypesResp, err := this.RPC().DNSProviderRPC().FindAllDNSProviderTypes(this.AdminContext(), &pb.FindAllDNSProviderTypesRequest{})
if err != nil { if err != nil {
@@ -70,6 +78,8 @@ func (this *UpdateClusterPopupAction) RunPost(params struct {
DomainId int64 DomainId int64
NodesAutoSync bool NodesAutoSync bool
ServersAutoSync bool ServersAutoSync bool
CnameRecords []string
Ttl int32
Must *actions.Must Must *actions.Must
CSRF *actionutils.CSRF CSRF *actionutils.CSRF
@@ -103,6 +113,8 @@ func (this *UpdateClusterPopupAction) RunPost(params struct {
DnsDomainId: params.DomainId, DnsDomainId: params.DomainId,
NodesAutoSync: params.NodesAutoSync, NodesAutoSync: params.NodesAutoSync,
ServersAutoSync: params.ServersAutoSync, ServersAutoSync: params.ServersAutoSync,
CnameRecords: params.CnameRecords,
Ttl: params.Ttl,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -30,20 +30,22 @@ func (this *CreatePopupAction) RunPost(params struct {
IP string `alias:"ip"` IP string `alias:"ip"`
CanAccess bool CanAccess bool
Name string Name string
IsUp bool
ThresholdsJSON []byte ThresholdsJSON []byte
Must *actions.Must Must *actions.Must
}) { }) {
ip := net.ParseIP(params.IP)
if len(ip) == 0 {
this.Fail("请输入正确的IP")
}
params.Must. params.Must.
Field("ip", params.IP). Field("ip", params.IP).
Require("请输入IP地址") Require("请输入IP地址")
var thresholds = []*nodeconfigs.NodeValueThresholdConfig{} ip := net.ParseIP(params.IP)
if len(ip) == 0 {
this.FailField("ip", "请输入正确的IP")
}
// 阈值设置
var thresholds = []*nodeconfigs.IPAddressThresholdConfig{}
if teaconst.IsPlus && len(params.ThresholdsJSON) > 0 { if teaconst.IsPlus && len(params.ThresholdsJSON) > 0 {
_ = json.Unmarshal(params.ThresholdsJSON, &thresholds) _ = json.Unmarshal(params.ThresholdsJSON, &thresholds)
} }
@@ -54,7 +56,7 @@ func (this *CreatePopupAction) RunPost(params struct {
"ip": params.IP, "ip": params.IP,
"id": 0, "id": 0,
"isOn": true, "isOn": true,
"isUp": true, "isUp": params.IsUp,
"thresholds": thresholds, "thresholds": thresholds,
} }
this.Success() this.Success()

View File

@@ -16,12 +16,6 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
return err return err
} }
for _, addr := range addresses { for _, addr := range addresses {
var thresholdsJSON = []byte{}
var thresholds = addr.GetSlice("thresholds")
if len(thresholds) > 0 {
thresholdsJSON, _ = json.Marshal(thresholds)
}
addrId := addr.GetInt64("id") addrId := addr.GetInt64("id")
if addrId > 0 { if addrId > 0 {
var isOn = false var isOn = false
@@ -37,19 +31,36 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
Name: addr.GetString("name"), Name: addr.GetString("name"),
CanAccess: addr.GetBool("canAccess"), CanAccess: addr.GetBool("canAccess"),
IsOn: isOn, IsOn: isOn,
ThresholdsJSON: thresholdsJSON, IsUp: addr.GetBool("isUp"),
}) })
if err != nil { if err != nil {
return err return err
} }
} else { } else {
_, err = parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddress(parentAction.AdminContext(), &pb.CreateNodeIPAddressRequest{ createResp, err := parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddress(parentAction.AdminContext(), &pb.CreateNodeIPAddressRequest{
NodeId: nodeId, NodeId: nodeId,
Role: role, Role: role,
Name: addr.GetString("name"), Name: addr.GetString("name"),
Ip: addr.GetString("ip"), Ip: addr.GetString("ip"),
CanAccess: addr.GetBool("canAccess"), CanAccess: addr.GetBool("canAccess"),
ThresholdsJSON: thresholdsJSON, IsUp: addr.GetBool("isUp"),
})
if err != nil {
return err
}
addrId = createResp.NodeIPAddressId
}
// 保存阈值
var thresholds = addr.GetSlice("thresholds")
if len(thresholds) > 0 {
thresholdsJSON, err := json.Marshal(thresholds)
if err != nil {
return err
}
_, err = parentAction.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(parentAction.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
NodeIPAddressId: addrId,
NodeIPAddressThresholdsJSON: thresholdsJSON,
}) })
if err != nil { if err != nil {
return err return err
@@ -58,3 +69,35 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
} }
return nil return nil
} }
// InitNodeIPAddressThresholds 初始化IP阈值
func InitNodeIPAddressThresholds(parentAction *actionutils.ParentAction, addrId int64) ([]*nodeconfigs.IPAddressThresholdConfig, error) {
thresholdsResp, err := parentAction.RPC().NodeIPAddressThresholdRPC().FindAllEnabledNodeIPAddressThresholds(parentAction.AdminContext(), &pb.FindAllEnabledNodeIPAddressThresholdsRequest{NodeIPAddressId: addrId})
if err != nil {
return nil, err
}
var thresholds = []*nodeconfigs.IPAddressThresholdConfig{}
if len(thresholdsResp.NodeIPAddressThresholds) > 0 {
for _, pbThreshold := range thresholdsResp.NodeIPAddressThresholds {
var threshold = &nodeconfigs.IPAddressThresholdConfig{
Id: pbThreshold.Id,
Items: []*nodeconfigs.IPAddressThresholdItemConfig{},
Actions: []*nodeconfigs.IPAddressThresholdActionConfig{},
}
if len(pbThreshold.ItemsJSON) > 0 {
err = json.Unmarshal(pbThreshold.ItemsJSON, &threshold.Items)
if err != nil {
return nil, err
}
}
if len(pbThreshold.ActionsJSON) > 0 {
err = json.Unmarshal(pbThreshold.ActionsJSON, &threshold.Actions)
if err != nil {
return nil, err
}
}
thresholds = append(thresholds, threshold)
}
}
return thresholds, nil
}

View File

@@ -34,6 +34,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
Name string Name string
CanAccess bool CanAccess bool
IsOn bool IsOn bool
IsUp bool
ThresholdsJSON []byte ThresholdsJSON []byte
Must *actions.Must Must *actions.Must
@@ -43,7 +44,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
Require("请输入IP地址") Require("请输入IP地址")
// 获取IP地址信息 // 获取IP地址信息
var isUp = true var isUp = params.IsUp
if params.AddressId > 0 { if params.AddressId > 0 {
addressResp, err := this.RPC().NodeIPAddressRPC().FindEnabledNodeIPAddress(this.AdminContext(), &pb.FindEnabledNodeIPAddressRequest{NodeIPAddressId: params.AddressId}) addressResp, err := this.RPC().NodeIPAddressRPC().FindEnabledNodeIPAddress(this.AdminContext(), &pb.FindEnabledNodeIPAddressRequest{NodeIPAddressId: params.AddressId})
if err != nil { if err != nil {
@@ -54,7 +55,6 @@ func (this *UpdatePopupAction) RunPost(params struct {
if address == nil { if address == nil {
this.Fail("找不到要修改的地址") this.Fail("找不到要修改的地址")
} }
isUp = address.IsUp
} }
ip := net.ParseIP(params.IP) ip := net.ParseIP(params.IP)
@@ -62,7 +62,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
this.Fail("请输入正确的IP") this.Fail("请输入正确的IP")
} }
var thresholds = []*nodeconfigs.NodeValueThresholdConfig{} var thresholds = []*nodeconfigs.IPAddressThresholdConfig{}
if teaconst.IsPlus && len(params.ThresholdsJSON) > 0 { if teaconst.IsPlus && len(params.ThresholdsJSON) > 0 {
_ = json.Unmarshal(params.ThresholdsJSON, &thresholds) _ = json.Unmarshal(params.ThresholdsJSON, &thresholds)
} }

View File

@@ -79,8 +79,8 @@ func (this *CreateNodeAction) RunPost(params struct {
nodeId := createResp.NsNodeId nodeId := createResp.NsNodeId
// IP地址 // IP地址
for _, address := range ipAddresses { for _, addrMap := range ipAddresses {
addressId := address.GetInt64("id") addressId := addrMap.GetInt64("id")
if addressId > 0 { if addressId > 0 {
_, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{ _, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{
NodeIPAddressId: addressId, NodeIPAddressId: addressId,
@@ -90,9 +90,10 @@ func (this *CreateNodeAction) RunPost(params struct {
_, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{ _, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
NodeId: nodeId, NodeId: nodeId,
Role: nodeconfigs.NodeRoleDNS, Role: nodeconfigs.NodeRoleDNS,
Name: address.GetString("name"), Name: addrMap.GetString("name"),
Ip: address.GetString("ip"), Ip: addrMap.GetString("ip"),
CanAccess: address.GetBool("canAccess"), CanAccess: addrMap.GetBool("canAccess"),
IsUp: addrMap.GetBool("isUp"),
}) })
} }
if err != nil { if err != nil {

View File

@@ -81,7 +81,7 @@ func (this *IndexAction) RunGet(params struct {
} }
// IP // IP
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{ ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
NodeId: node.Id, NodeId: node.Id,
Role: nodeconfigs.NodeRoleDNS, Role: nodeconfigs.NodeRoleDNS,
}) })
@@ -90,7 +90,7 @@ func (this *IndexAction) RunGet(params struct {
return return
} }
ipAddresses := []maps.Map{} ipAddresses := []maps.Map{}
for _, addr := range ipAddressesResp.Addresses { for _, addr := range ipAddressesResp.NodeIPAddresses {
ipAddresses = append(ipAddresses, maps.Map{ ipAddresses = append(ipAddresses, maps.Map{
"id": addr.Id, "id": addr.Id,
"name": addr.Name, "name": addr.Name,

View File

@@ -56,7 +56,7 @@ func (this *IndexAction) RunGet(params struct {
} }
// IP地址 // IP地址
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{ ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
Role: nodeconfigs.NodeRoleDNS, Role: nodeconfigs.NodeRoleDNS,
}) })
@@ -65,7 +65,7 @@ func (this *IndexAction) RunGet(params struct {
return return
} }
ipAddressMaps := []maps.Map{} ipAddressMaps := []maps.Map{}
for _, addr := range ipAddressesResp.Addresses { for _, addr := range ipAddressesResp.NodeIPAddresses {
ipAddressMaps = append(ipAddressMaps, maps.Map{ ipAddressMaps = append(ipAddressMaps, maps.Map{
"id": addr.Id, "id": addr.Id,
"name": addr.Name, "name": addr.Name,

View File

@@ -46,7 +46,7 @@ func (this *UpdateAction) RunGet(params struct {
} }
// IP地址 // IP地址
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{ ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
Role: nodeconfigs.NodeRoleDNS, Role: nodeconfigs.NodeRoleDNS,
}) })
@@ -55,7 +55,7 @@ func (this *UpdateAction) RunGet(params struct {
return return
} }
ipAddressMaps := []maps.Map{} ipAddressMaps := []maps.Map{}
for _, addr := range ipAddressesResp.Addresses { for _, addr := range ipAddressesResp.NodeIPAddresses {
ipAddressMaps = append(ipAddressMaps, maps.Map{ ipAddressMaps = append(ipAddressMaps, maps.Map{
"id": addr.Id, "id": addr.Id,
"name": addr.Name, "name": addr.Name,
@@ -213,7 +213,7 @@ func (this *UpdateAction) RunPost(params struct {
} }
// 禁用老的IP地址 // 禁用老的IP地址
_, err = this.RPC().NodeIPAddressRPC().DisableAllIPAddressesWithNodeId(this.AdminContext(), &pb.DisableAllIPAddressesWithNodeIdRequest{ _, err = this.RPC().NodeIPAddressRPC().DisableAllNodeIPAddressesWithNodeId(this.AdminContext(), &pb.DisableAllNodeIPAddressesWithNodeIdRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
Role: nodeconfigs.NodeRoleDNS, Role: nodeconfigs.NodeRoleDNS,
}) })

View File

@@ -28,7 +28,7 @@ func (this *NodeOptionsAction) RunPost(params struct {
continue continue
} }
addressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{ addressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
NodeId: node.Id, NodeId: node.Id,
Role: nodeconfigs.NodeRoleDNS, Role: nodeconfigs.NodeRoleDNS,
}) })
@@ -36,7 +36,7 @@ func (this *NodeOptionsAction) RunPost(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
var addresses = addressesResp.Addresses var addresses = addressesResp.NodeIPAddresses
if len(addresses) == 0 { if len(addresses) == 0 {
continue continue
} }

View File

@@ -1,4 +1,4 @@
package groups package group
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs" "github.com/TeaOSLab/EdgeAdmin/internal/oplogs"

View File

@@ -0,0 +1,193 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package group
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"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("", "", "group.index")
}
func (this *IndexAction) RunGet(params struct {
GroupId int64
Keyword string
}) {
this.Data["keyword"] = params.Keyword
group, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "")
if err != nil {
this.ErrorPage(err)
return
}
this.Data["group"] = maps.Map{
"id": group.Id,
"name": group.Name,
}
// 是否有用户管理权限
this.Data["canVisitUser"] = configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeUser)
// 服务列表
countResp, err := this.RPC().ServerRPC().CountAllEnabledServersMatch(this.AdminContext(), &pb.CountAllEnabledServersMatchRequest{
ServerGroupId: params.GroupId,
Keyword: params.Keyword,
})
if err != nil {
this.ErrorPage(err)
return
}
count := countResp.Count
page := this.NewPage(count)
this.Data["page"] = page.AsHTML()
// 服务列表
serversResp, err := this.RPC().ServerRPC().ListEnabledServersMatch(this.AdminContext(), &pb.ListEnabledServersMatchRequest{
Offset: page.Offset,
Size: page.Size,
ServerGroupId: params.GroupId,
Keyword: params.Keyword,
})
if err != nil {
this.ErrorPage(err)
return
}
serverMaps := []maps.Map{}
for _, server := range serversResp.Servers {
config := &serverconfigs.ServerConfig{}
err = json.Unmarshal(server.Config, config)
if err != nil {
this.ErrorPage(err)
return
}
// 端口列表
portMaps := []maps.Map{}
if len(server.HttpJSON) > 0 && config.HTTP.IsOn {
for _, listen := range config.HTTP.Listen {
portMaps = append(portMaps, maps.Map{
"protocol": listen.Protocol,
"portRange": listen.PortRange,
})
}
}
if config.HTTPS != nil && config.HTTPS.IsOn {
for _, listen := range config.HTTPS.Listen {
portMaps = append(portMaps, maps.Map{
"protocol": listen.Protocol,
"portRange": listen.PortRange,
})
}
}
if config.TCP != nil && config.TCP.IsOn {
for _, listen := range config.TCP.Listen {
portMaps = append(portMaps, maps.Map{
"protocol": listen.Protocol,
"portRange": listen.PortRange,
})
}
}
if config.TLS != nil && config.TLS.IsOn {
for _, listen := range config.TLS.Listen {
portMaps = append(portMaps, maps.Map{
"protocol": listen.Protocol,
"portRange": listen.PortRange,
})
}
}
if config.Unix != nil && config.Unix.IsOn {
for _, listen := range config.Unix.Listen {
portMaps = append(portMaps, maps.Map{
"protocol": listen.Protocol,
"portRange": listen.Host,
})
}
}
if config.UDP != nil && config.UDP.IsOn {
for _, listen := range config.UDP.Listen {
portMaps = append(portMaps, maps.Map{
"protocol": listen.Protocol,
"portRange": listen.PortRange,
})
}
}
// 分组
groupMaps := []maps.Map{}
if len(server.ServerGroups) > 0 {
for _, group := range server.ServerGroups {
groupMaps = append(groupMaps, maps.Map{
"id": group.Id,
"name": group.Name,
})
}
}
// 域名列表
serverNames := []*serverconfigs.ServerNameConfig{}
if server.IsAuditing || (server.AuditingResult != nil && !server.AuditingResult.IsOk) {
server.ServerNamesJSON = server.AuditingServerNamesJSON
}
auditingIsOk := true
if !server.IsAuditing && server.AuditingResult != nil && !server.AuditingResult.IsOk {
auditingIsOk = false
}
if len(server.ServerNamesJSON) > 0 {
err = json.Unmarshal(server.ServerNamesJSON, &serverNames)
if err != nil {
this.ErrorPage(err)
return
}
}
countServerNames := 0
for _, serverName := range serverNames {
if len(serverName.SubNames) == 0 {
countServerNames++
} else {
countServerNames += len(serverName.SubNames)
}
}
// 用户
var userMap maps.Map = nil
if server.User != nil {
userMap = maps.Map{
"id": server.User.Id,
"fullname": server.User.Fullname,
}
}
serverMaps = append(serverMaps, maps.Map{
"id": server.Id,
"isOn": server.IsOn,
"name": server.Name,
"cluster": maps.Map{
"id": server.NodeCluster.Id,
"name": server.NodeCluster.Name,
},
"ports": portMaps,
"serverTypeName": serverconfigs.FindServerType(server.Type).GetString("name"),
"groups": groupMaps,
"serverNames": serverNames,
"countServerNames": countServerNames,
"isAuditing": server.IsAuditing,
"auditingIsOk": auditingIsOk,
"user": userMap,
})
}
this.Data["servers"] = serverMaps
this.Show()
}

View File

@@ -0,0 +1,110 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package servergrouputils
import (
"errors"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
// InitGroup 初始化分组信息
func InitGroup(parent *actionutils.ParentAction, groupId int64, menuItem string) (*pb.ServerGroup, error) {
groupResp, err := parent.RPC().ServerGroupRPC().FindEnabledServerGroup(parent.AdminContext(), &pb.FindEnabledServerGroupRequest{ServerGroupId: groupId})
if err != nil {
return nil, err
}
var group = groupResp.ServerGroup
if group == nil {
return nil, errors.New("group with id '" + types.String(groupId) + "' not found")
}
parent.Data["group"] = maps.Map{
"id": group.Id,
"name": group.Name,
}
// 初始化设置菜单
if len(menuItem) > 0 {
// 获取设置概要信息
configInfoResp, err := parent.RPC().ServerGroupRPC().FindEnabledServerGroupConfigInfo(parent.AdminContext(), &pb.FindEnabledServerGroupConfigInfoRequest{ServerGroupId: groupId})
if err != nil {
return group, err
}
var urlPrefix = "/servers/groups/group/settings"
parent.Data["leftMenuItems"] = []maps.Map{
/**{
"name": "Web设置",
"url": urlPrefix + "/web?groupId=" + types.String(groupId),
"isActive": menuItem == "web",
},**/
{
"name": "HTTP反向代理",
"url": urlPrefix + "/httpReverseProxy?groupId=" + types.String(groupId),
"isActive": menuItem == "httpReverseProxy",
"isOn": configInfoResp.HasHTTPReverseProxy,
},
{
"name": "TCP反向代理",
"url": urlPrefix + "/tcpReverseProxy?groupId=" + types.String(groupId),
"isActive": menuItem == "tcpReverseProxy",
"isOn": configInfoResp.HasTCPReverseProxy,
},
{
"name": "UDP反向代理",
"url": urlPrefix + "/udpReverseProxy?groupId=" + types.String(groupId),
"isActive": menuItem == "udpReverseProxy",
"isOn": configInfoResp.HasUDPReverseProxy,
},
/**{
"name": "-",
"url": "",
},
{
"name": "WAF",
"url": urlPrefix + "/waf?groupId=" + types.String(groupId),
"isActive": menuItem == "waf",
},
{
"name": "缓存",
"url": urlPrefix + "/cache?groupId=" + types.String(groupId),
"isActive": menuItem == "cache",
},
{
"name": "访问日志",
"url": urlPrefix + "/accessLog?groupId=" + types.String(groupId),
"isActive": menuItem == "accessLog",
},
{
"name": "统计",
"url": urlPrefix + "/stat?groupId=" + types.String(groupId),
"isActive": menuItem == "stat",
},
{
"name": "Gzip压缩",
"url": urlPrefix + "/gzip?groupId=" + types.String(groupId),
"isActive": menuItem == "gzip",
},
{
"name": "特殊页面",
"url": urlPrefix + "/pages?groupId=" + types.String(groupId),
"isActive": menuItem == "page",
},
{
"name": "HTTP Header",
"url": urlPrefix + "/headers?groupId=" + types.String(groupId),
"isActive": menuItem == "header",
},
{
"name": "Websocket",
"url": urlPrefix + "/websocket?groupId=" + types.String(groupId),
"isActive": menuItem == "websocket",
},**/
}
}
return group, nil
}

View File

@@ -0,0 +1,87 @@
package httpReverseProxy
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/maps"
)
// IndexAction 源站列表
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.FirstMenu("index")
}
func (this *IndexAction) RunGet(params struct {
GroupId int64
}) {
_, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "httpReverseProxy")
if err != nil {
this.ErrorPage(err)
return
}
this.Data["serverType"] = "httpProxy"
reverseProxyResp, err := this.RPC().ServerGroupRPC().FindAndInitServerGroupHTTPReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerGroupHTTPReverseProxyConfigRequest{ServerGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyRef"] = reverseProxyRef
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyConfig"] = reverseProxy
primaryOriginMaps := []maps.Map{}
backupOriginMaps := []maps.Map{}
for _, originConfig := range reverseProxy.PrimaryOrigins {
if len(originConfig.Domains) == 0 {
originConfig.Domains = []string{}
}
m := maps.Map{
"id": originConfig.Id,
"weight": originConfig.Weight,
"addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange,
"name": originConfig.Name,
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
}
primaryOriginMaps = append(primaryOriginMaps, m)
}
for _, originConfig := range reverseProxy.BackupOrigins {
if len(originConfig.Domains) == 0 {
originConfig.Domains = []string{}
}
m := maps.Map{
"id": originConfig.Id,
"weight": originConfig.Weight,
"addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange,
"name": originConfig.Name,
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
}
backupOriginMaps = append(backupOriginMaps, m)
}
this.Data["primaryOrigins"] = primaryOriginMaps
this.Data["backupOrigins"] = backupOriginMaps
this.Show()
}

View File

@@ -0,0 +1,21 @@
package httpReverseProxy
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
Data("teaMenu", "servers").
Data("teaSubMenu", "group").
Prefix("/servers/groups/group/settings/httpReverseProxy").
Get("", new(IndexAction)).
GetPost("/scheduling", new(SchedulingAction)).
GetPost("/setting", new(SettingAction)).
EndAll()
})
}

View File

@@ -0,0 +1,54 @@
package httpReverseProxy
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/schedulingconfigs"
)
type SchedulingAction struct {
actionutils.ParentAction
}
func (this *SchedulingAction) Init() {
this.FirstMenu("scheduling")
}
func (this *SchedulingAction) RunGet(params struct {
GroupId int64
}) {
_, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "httpReverseProxy")
if err != nil {
this.ErrorPage(err)
return
}
this.Data["family"] = "http"
reverseProxyResp, err := this.RPC().ServerGroupRPC().FindAndInitServerGroupHTTPReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerGroupHTTPReverseProxyConfigRequest{ServerGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyId"] = reverseProxy.Id
schedulingCode := reverseProxy.FindSchedulingConfig().Code
schedulingMap := schedulingconfigs.FindSchedulingType(schedulingCode)
if schedulingMap == nil {
this.ErrorPage(errors.New("invalid scheduling code '" + schedulingCode + "'"))
return
}
this.Data["scheduling"] = schedulingMap
this.Show()
}

View File

@@ -0,0 +1,102 @@
package httpReverseProxy
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/types"
)
type SettingAction struct {
actionutils.ParentAction
}
func (this *SettingAction) Init() {
this.FirstMenu("setting")
}
func (this *SettingAction) RunGet(params struct {
GroupId int64
}) {
_, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "httpReverseProxy")
if err != nil {
this.ErrorPage(err)
return
}
this.Data["family"] = "http"
reverseProxyResp, err := this.RPC().ServerGroupRPC().FindAndInitServerGroupHTTPReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerGroupHTTPReverseProxyConfigRequest{ServerGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
if err != nil {
this.ErrorPage(err)
return
}
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyRef"] = reverseProxyRef
this.Data["reverseProxyConfig"] = reverseProxy
this.Show()
}
func (this *SettingAction) RunPost(params struct {
GroupId int64
ReverseProxyRefJSON []byte
ReverseProxyJSON []byte
Must *actions.Must
}) {
defer this.CreateLogInfo("修改分组 %d 的反向代理设置", params.GroupId)
// TODO 校验配置
reverseProxyConfig := &serverconfigs.ReverseProxyConfig{}
err := json.Unmarshal(params.ReverseProxyJSON, reverseProxyConfig)
if err != nil {
this.ErrorPage(err)
return
}
err = reverseProxyConfig.Init()
if err != nil {
this.Fail("配置校验失败:" + err.Error())
}
// 设置是否启用
_, err = this.RPC().ServerGroupRPC().UpdateServerGroupHTTPReverseProxy(this.AdminContext(), &pb.UpdateServerGroupHTTPReverseProxyRequest{
ServerGroupId: params.GroupId,
ReverseProxyJSON: params.ReverseProxyRefJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
// 设置反向代理相关信息
_, err = this.RPC().ReverseProxyRPC().UpdateReverseProxy(this.AdminContext(), &pb.UpdateReverseProxyRequest{
ReverseProxyId: reverseProxyConfig.Id,
RequestHostType: types.Int32(reverseProxyConfig.RequestHostType),
RequestHost: reverseProxyConfig.RequestHost,
RequestURI: reverseProxyConfig.RequestURI,
StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush,
AddHeaders: reverseProxyConfig.AddHeaders,
})
this.Success()
}

View File

@@ -0,0 +1,23 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package reverseProxy
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/types"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "")
}
func (this *IndexAction) RunGet(params struct {
GroupId int64
}) {
this.RedirectURL("/servers/groups/group/settings/httpReverseProxy?groupId=" + types.String(params.GroupId))
return
}

View File

@@ -0,0 +1,22 @@
package reverseProxy
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/locationutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/serverutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
Helper(locationutils.NewLocationHelper()).
Helper(serverutils.NewServerHelper()).
Data("mainTab", "setting").
Prefix("/servers/groups/group/settings").
Get("", new(IndexAction)).
EndAll()
})
}

View File

@@ -0,0 +1,87 @@
package tcpReverseProxy
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/maps"
)
// IndexAction 源站列表
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.FirstMenu("index")
}
func (this *IndexAction) RunGet(params struct {
GroupId int64
}) {
_, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "tcpReverseProxy")
if err != nil {
this.ErrorPage(err)
return
}
this.Data["serverType"] = "tcpProxy"
reverseProxyResp, err := this.RPC().ServerGroupRPC().FindAndInitServerGroupTCPReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerGroupTCPReverseProxyConfigRequest{ServerGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyRef"] = reverseProxyRef
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyConfig"] = reverseProxy
primaryOriginMaps := []maps.Map{}
backupOriginMaps := []maps.Map{}
for _, originConfig := range reverseProxy.PrimaryOrigins {
if len(originConfig.Domains) == 0 {
originConfig.Domains = []string{}
}
m := maps.Map{
"id": originConfig.Id,
"weight": originConfig.Weight,
"addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange,
"name": originConfig.Name,
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
}
primaryOriginMaps = append(primaryOriginMaps, m)
}
for _, originConfig := range reverseProxy.BackupOrigins {
if len(originConfig.Domains) == 0 {
originConfig.Domains = []string{}
}
m := maps.Map{
"id": originConfig.Id,
"weight": originConfig.Weight,
"addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange,
"name": originConfig.Name,
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
}
backupOriginMaps = append(backupOriginMaps, m)
}
this.Data["primaryOrigins"] = primaryOriginMaps
this.Data["backupOrigins"] = backupOriginMaps
this.Show()
}

View File

@@ -0,0 +1,21 @@
package tcpReverseProxy
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
Data("teaMenu", "servers").
Data("teaSubMenu", "group").
Prefix("/servers/groups/group/settings/tcpReverseProxy").
Get("", new(IndexAction)).
GetPost("/scheduling", new(SchedulingAction)).
GetPost("/setting", new(SettingAction)).
EndAll()
})
}

View File

@@ -0,0 +1,54 @@
package tcpReverseProxy
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/schedulingconfigs"
)
type SchedulingAction struct {
actionutils.ParentAction
}
func (this *SchedulingAction) Init() {
this.FirstMenu("scheduling")
}
func (this *SchedulingAction) RunGet(params struct {
GroupId int64
}) {
_, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "tcpReverseProxy")
if err != nil {
this.ErrorPage(err)
return
}
this.Data["family"] = "tcp"
reverseProxyResp, err := this.RPC().ServerGroupRPC().FindAndInitServerGroupTCPReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerGroupTCPReverseProxyConfigRequest{ServerGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyId"] = reverseProxy.Id
schedulingCode := reverseProxy.FindSchedulingConfig().Code
schedulingMap := schedulingconfigs.FindSchedulingType(schedulingCode)
if schedulingMap == nil {
this.ErrorPage(errors.New("invalid scheduling code '" + schedulingCode + "'"))
return
}
this.Data["scheduling"] = schedulingMap
this.Show()
}

View File

@@ -0,0 +1,102 @@
package tcpReverseProxy
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/types"
)
type SettingAction struct {
actionutils.ParentAction
}
func (this *SettingAction) Init() {
this.FirstMenu("setting")
}
func (this *SettingAction) RunGet(params struct {
GroupId int64
}) {
_, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "tcpReverseProxy")
if err != nil {
this.ErrorPage(err)
return
}
this.Data["family"] = "tcp"
reverseProxyResp, err := this.RPC().ServerGroupRPC().FindAndInitServerGroupTCPReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerGroupTCPReverseProxyConfigRequest{ServerGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
if err != nil {
this.ErrorPage(err)
return
}
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyRef"] = reverseProxyRef
this.Data["reverseProxyConfig"] = reverseProxy
this.Show()
}
func (this *SettingAction) RunPost(params struct {
GroupId int64
ReverseProxyRefJSON []byte
ReverseProxyJSON []byte
Must *actions.Must
}) {
defer this.CreateLogInfo("修改分组 %d 的反向代理设置", params.GroupId)
// TODO 校验配置
reverseProxyConfig := &serverconfigs.ReverseProxyConfig{}
err := json.Unmarshal(params.ReverseProxyJSON, reverseProxyConfig)
if err != nil {
this.ErrorPage(err)
return
}
err = reverseProxyConfig.Init()
if err != nil {
this.Fail("配置校验失败:" + err.Error())
}
// 设置是否启用
_, err = this.RPC().ServerGroupRPC().UpdateServerGroupTCPReverseProxy(this.AdminContext(), &pb.UpdateServerGroupTCPReverseProxyRequest{
ServerGroupId: params.GroupId,
ReverseProxyJSON: params.ReverseProxyRefJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
// 设置反向代理相关信息
_, err = this.RPC().ReverseProxyRPC().UpdateReverseProxy(this.AdminContext(), &pb.UpdateReverseProxyRequest{
ReverseProxyId: reverseProxyConfig.Id,
RequestHostType: types.Int32(reverseProxyConfig.RequestHostType),
RequestHost: reverseProxyConfig.RequestHost,
RequestURI: reverseProxyConfig.RequestURI,
StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush,
AddHeaders: reverseProxyConfig.AddHeaders,
})
this.Success()
}

View File

@@ -0,0 +1,87 @@
package udpReverseProxy
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/maps"
)
// IndexAction 源站列表
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.FirstMenu("index")
}
func (this *IndexAction) RunGet(params struct {
GroupId int64
}) {
_, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "udpReverseProxy")
if err != nil {
this.ErrorPage(err)
return
}
this.Data["serverType"] = "udpProxy"
reverseProxyResp, err := this.RPC().ServerGroupRPC().FindAndInitServerGroupUDPReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerGroupUDPReverseProxyConfigRequest{ServerGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyRef"] = reverseProxyRef
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyConfig"] = reverseProxy
primaryOriginMaps := []maps.Map{}
backupOriginMaps := []maps.Map{}
for _, originConfig := range reverseProxy.PrimaryOrigins {
if len(originConfig.Domains) == 0 {
originConfig.Domains = []string{}
}
m := maps.Map{
"id": originConfig.Id,
"weight": originConfig.Weight,
"addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange,
"name": originConfig.Name,
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
}
primaryOriginMaps = append(primaryOriginMaps, m)
}
for _, originConfig := range reverseProxy.BackupOrigins {
if len(originConfig.Domains) == 0 {
originConfig.Domains = []string{}
}
m := maps.Map{
"id": originConfig.Id,
"weight": originConfig.Weight,
"addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange,
"name": originConfig.Name,
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
}
backupOriginMaps = append(backupOriginMaps, m)
}
this.Data["primaryOrigins"] = primaryOriginMaps
this.Data["backupOrigins"] = backupOriginMaps
this.Show()
}

View File

@@ -0,0 +1,21 @@
package udpReverseProxy
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
Data("teaMenu", "servers").
Data("teaSubMenu", "group").
Prefix("/servers/groups/group/settings/udpReverseProxy").
Get("", new(IndexAction)).
GetPost("/scheduling", new(SchedulingAction)).
GetPost("/setting", new(SettingAction)).
EndAll()
})
}

View File

@@ -0,0 +1,54 @@
package udpReverseProxy
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/schedulingconfigs"
)
type SchedulingAction struct {
actionutils.ParentAction
}
func (this *SchedulingAction) Init() {
this.FirstMenu("scheduling")
}
func (this *SchedulingAction) RunGet(params struct {
GroupId int64
}) {
_, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "udpReverseProxy")
if err != nil {
this.ErrorPage(err)
return
}
this.Data["family"] = "udp"
reverseProxyResp, err := this.RPC().ServerGroupRPC().FindAndInitServerGroupUDPReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerGroupUDPReverseProxyConfigRequest{ServerGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyId"] = reverseProxy.Id
schedulingCode := reverseProxy.FindSchedulingConfig().Code
schedulingMap := schedulingconfigs.FindSchedulingType(schedulingCode)
if schedulingMap == nil {
this.ErrorPage(errors.New("invalid scheduling code '" + schedulingCode + "'"))
return
}
this.Data["scheduling"] = schedulingMap
this.Show()
}

View File

@@ -0,0 +1,102 @@
package udpReverseProxy
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/types"
)
type SettingAction struct {
actionutils.ParentAction
}
func (this *SettingAction) Init() {
this.FirstMenu("setting")
}
func (this *SettingAction) RunGet(params struct {
GroupId int64
}) {
_, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "udpReverseProxy")
if err != nil {
this.ErrorPage(err)
return
}
this.Data["family"] = "udp"
reverseProxyResp, err := this.RPC().ServerGroupRPC().FindAndInitServerGroupUDPReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerGroupUDPReverseProxyConfigRequest{ServerGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
if err != nil {
this.ErrorPage(err)
return
}
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyRef"] = reverseProxyRef
this.Data["reverseProxyConfig"] = reverseProxy
this.Show()
}
func (this *SettingAction) RunPost(params struct {
GroupId int64
ReverseProxyRefJSON []byte
ReverseProxyJSON []byte
Must *actions.Must
}) {
defer this.CreateLogInfo("修改分组 %d 的反向代理设置", params.GroupId)
// TODO 校验配置
reverseProxyConfig := &serverconfigs.ReverseProxyConfig{}
err := json.Unmarshal(params.ReverseProxyJSON, reverseProxyConfig)
if err != nil {
this.ErrorPage(err)
return
}
err = reverseProxyConfig.Init()
if err != nil {
this.Fail("配置校验失败:" + err.Error())
}
// 设置是否启用
_, err = this.RPC().ServerGroupRPC().UpdateServerGroupUDPReverseProxy(this.AdminContext(), &pb.UpdateServerGroupUDPReverseProxyRequest{
ServerGroupId: params.GroupId,
ReverseProxyJSON: params.ReverseProxyRefJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
// 设置反向代理相关信息
_, err = this.RPC().ReverseProxyRPC().UpdateReverseProxy(this.AdminContext(), &pb.UpdateReverseProxyRequest{
ReverseProxyId: reverseProxyConfig.Id,
RequestHostType: types.Int32(reverseProxyConfig.RequestHostType),
RequestHost: reverseProxyConfig.RequestHost,
RequestURI: reverseProxyConfig.RequestURI,
StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush,
AddHeaders: reverseProxyConfig.AddHeaders,
})
this.Success()
}

View File

@@ -1,34 +1,30 @@
package groups package group
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs" "github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/servergrouputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
) )
type UpdatePopupAction struct { type UpdateAction struct {
actionutils.ParentAction actionutils.ParentAction
} }
func (this *UpdatePopupAction) Init() { func (this *UpdateAction) Init() {
this.Nav("", "", "") this.Nav("", "", "group.update")
} }
func (this *UpdatePopupAction) RunGet(params struct { func (this *UpdateAction) RunGet(params struct {
GroupId int64 GroupId int64
}) { }) {
groupResp, err := this.RPC().ServerGroupRPC().FindEnabledServerGroup(this.AdminContext(), &pb.FindEnabledServerGroupRequest{ServerGroupId: params.GroupId}) group, err := servergrouputils.InitGroup(this.Parent(), params.GroupId, "")
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
group := groupResp.ServerGroup
if group == nil {
this.NotFound("serverGroup", params.GroupId)
return
}
this.Data["group"] = maps.Map{ this.Data["group"] = maps.Map{
"id": group.Id, "id": group.Id,
@@ -38,7 +34,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
this.Show() this.Show()
} }
func (this *UpdatePopupAction) RunPost(params struct { func (this *UpdateAction) RunPost(params struct {
GroupId int64 GroupId int64
Name string Name string

View File

@@ -2,6 +2,7 @@ package groups
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders" "github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo" "github.com/iwind/TeaGo"
) )
@@ -12,13 +13,17 @@ func init() {
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)). Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
Helper(NewHelper()). Helper(NewHelper()).
Data("teaSubMenu", "group"). Data("teaSubMenu", "group").
Prefix("/servers/components/groups"). Prefix("/servers/groups").
Get("", new(IndexAction)). Get("", new(IndexAction)).
GetPost("/createPopup", new(CreatePopupAction)). GetPost("/createPopup", new(CreatePopupAction)).
GetPost("/updatePopup", new(UpdatePopupAction)).
GetPost("/selectPopup", new(SelectPopupAction)). GetPost("/selectPopup", new(SelectPopupAction)).
Post("/delete", new(DeleteAction)).
Post("/sort", new(SortAction)). Post("/sort", new(SortAction)).
// 详情
Prefix("/servers/groups/group").
Get("", new(group.IndexAction)).
Post("/delete", new(group.DeleteAction)).
GetPost("/update", new(group.UpdateAction)).
EndAll() EndAll()
}) })
} }

View File

@@ -54,22 +54,30 @@ func (this *IndexAction) RunGet(params struct {
primaryOriginMaps := []maps.Map{} primaryOriginMaps := []maps.Map{}
backupOriginMaps := []maps.Map{} backupOriginMaps := []maps.Map{}
for _, originConfig := range reverseProxy.PrimaryOrigins { for _, originConfig := range reverseProxy.PrimaryOrigins {
if len(originConfig.Domains) == 0 {
originConfig.Domains = []string{}
}
m := maps.Map{ m := maps.Map{
"id": originConfig.Id, "id": originConfig.Id,
"weight": originConfig.Weight, "weight": originConfig.Weight,
"addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange, "addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange,
"name": originConfig.Name, "name": originConfig.Name,
"isOn": originConfig.IsOn, "isOn": originConfig.IsOn,
"domains": originConfig.Domains,
} }
primaryOriginMaps = append(primaryOriginMaps, m) primaryOriginMaps = append(primaryOriginMaps, m)
} }
for _, originConfig := range reverseProxy.BackupOrigins { for _, originConfig := range reverseProxy.BackupOrigins {
if len(originConfig.Domains) == 0 {
originConfig.Domains = []string{}
}
m := maps.Map{ m := maps.Map{
"id": originConfig.Id, "id": originConfig.Id,
"weight": originConfig.Weight, "weight": originConfig.Weight,
"addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange, "addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange,
"name": originConfig.Name, "name": originConfig.Name,
"isOn": originConfig.IsOn, "isOn": originConfig.IsOn,
"domains": originConfig.Domains,
} }
backupOriginMaps = append(backupOriginMaps, m) backupOriginMaps = append(backupOriginMaps, m)
} }

View File

@@ -21,18 +21,24 @@ type AddPopupAction struct {
func (this *AddPopupAction) RunGet(params struct { func (this *AddPopupAction) RunGet(params struct {
ServerId int64 ServerId int64
ServerType string
ReverseProxyId int64 ReverseProxyId int64
OriginType string OriginType string
}) { }) {
this.Data["reverseProxyId"] = params.ReverseProxyId this.Data["reverseProxyId"] = params.ReverseProxyId
this.Data["originType"] = params.OriginType this.Data["originType"] = params.OriginType
serverTypeResp, err := this.RPC().ServerRPC().FindEnabledServerType(this.AdminContext(), &pb.FindEnabledServerTypeRequest{ServerId: params.ServerId}) var serverType = ""
if err != nil { if params.ServerId > 0 {
this.ErrorPage(err) serverTypeResp, err := this.RPC().ServerRPC().FindEnabledServerType(this.AdminContext(), &pb.FindEnabledServerTypeRequest{ServerId: params.ServerId})
return if err != nil {
this.ErrorPage(err)
return
}
serverType = serverTypeResp.Type
} else {
serverType = params.ServerType
} }
serverType := serverTypeResp.Type
this.Data["serverType"] = serverType this.Data["serverType"] = serverType
// 是否为HTTP // 是否为HTTP
@@ -56,6 +62,8 @@ func (this *AddPopupAction) RunPost(params struct {
MaxIdleConns int32 MaxIdleConns int32
IdleTimeout int IdleTimeout int
DomainsJSON []byte
Description string Description string
IsOn bool IsOn bool
@@ -121,6 +129,15 @@ func (this *AddPopupAction) RunPost(params struct {
return return
} }
var domains = []string{}
if len(params.DomainsJSON) > 0 {
err = json.Unmarshal(params.DomainsJSON, &domains)
if err != nil {
this.ErrorPage(err)
return
}
}
createResp, err := this.RPC().OriginRPC().CreateOrigin(this.AdminContext(), &pb.CreateOriginRequest{ createResp, err := this.RPC().OriginRPC().CreateOrigin(this.AdminContext(), &pb.CreateOriginRequest{
Name: params.Name, Name: params.Name,
Addr: &pb.NetworkAddress{ Addr: &pb.NetworkAddress{
@@ -136,6 +153,7 @@ func (this *AddPopupAction) RunPost(params struct {
IdleTimeoutJSON: idleTimeoutJSON, IdleTimeoutJSON: idleTimeoutJSON,
MaxConns: params.MaxConns, MaxConns: params.MaxConns,
MaxIdleConns: params.MaxIdleConns, MaxIdleConns: params.MaxIdleConns,
Domains: domains,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -26,6 +26,7 @@ func (this *UpdatePopupAction) Init() {
func (this *UpdatePopupAction) RunGet(params struct { func (this *UpdatePopupAction) RunGet(params struct {
ServerId int64 ServerId int64
ServerType string
ReverseProxyId int64 ReverseProxyId int64
OriginType string OriginType string
OriginId int64 OriginId int64
@@ -34,15 +35,20 @@ func (this *UpdatePopupAction) RunGet(params struct {
this.Data["reverseProxyId"] = params.ReverseProxyId this.Data["reverseProxyId"] = params.ReverseProxyId
this.Data["originId"] = params.OriginId this.Data["originId"] = params.OriginId
serverTypeResp, err := this.RPC().ServerRPC().FindEnabledServerType(this.AdminContext(), &pb.FindEnabledServerTypeRequest{ var serverType = ""
ServerId: params.ServerId, if params.ServerId > 0 {
}) serverTypeResp, err := this.RPC().ServerRPC().FindEnabledServerType(this.AdminContext(), &pb.FindEnabledServerTypeRequest{
if err != nil { ServerId: params.ServerId,
this.ErrorPage(err) })
return if err != nil {
this.ErrorPage(err)
return
}
serverType = serverTypeResp.Type
} else {
serverType = params.ServerType
} }
this.Data["serverType"] = serverTypeResp.Type this.Data["serverType"] = serverType
serverType := serverTypeResp.Type
// 是否为HTTP // 是否为HTTP
this.Data["isHTTP"] = serverType == "httpProxy" || serverType == "httpWeb" this.Data["isHTTP"] = serverType == "httpProxy" || serverType == "httpWeb"
@@ -76,6 +82,10 @@ func (this *UpdatePopupAction) RunGet(params struct {
idleTimeout = types.Int(config.IdleTimeout.Count) idleTimeout = types.Int(config.IdleTimeout.Count)
} }
if len(config.Domains) == 0 {
config.Domains = []string{}
}
this.Data["origin"] = maps.Map{ this.Data["origin"] = maps.Map{
"id": config.Id, "id": config.Id,
"protocol": config.Addr.Protocol, "protocol": config.Addr.Protocol,
@@ -89,6 +99,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
"idleTimeout": idleTimeout, "idleTimeout": idleTimeout,
"maxConns": config.MaxConns, "maxConns": config.MaxConns,
"maxIdleConns": config.MaxIdleConns, "maxIdleConns": config.MaxIdleConns,
"domains": config.Domains,
} }
this.Show() this.Show()
@@ -110,6 +121,8 @@ func (this *UpdatePopupAction) RunPost(params struct {
MaxIdleConns int32 MaxIdleConns int32
IdleTimeout int IdleTimeout int
DomainsJSON []byte
Description string Description string
IsOn bool IsOn bool
@@ -175,6 +188,15 @@ func (this *UpdatePopupAction) RunPost(params struct {
return return
} }
var domains = []string{}
if len(params.DomainsJSON) > 0 {
err = json.Unmarshal(params.DomainsJSON, &domains)
if err != nil {
this.ErrorPage(err)
return
}
}
_, err = this.RPC().OriginRPC().UpdateOrigin(this.AdminContext(), &pb.UpdateOriginRequest{ _, err = this.RPC().OriginRPC().UpdateOrigin(this.AdminContext(), &pb.UpdateOriginRequest{
OriginId: params.OriginId, OriginId: params.OriginId,
Name: params.Name, Name: params.Name,
@@ -191,6 +213,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
IdleTimeoutJSON: idleTimeoutJSON, IdleTimeoutJSON: idleTimeoutJSON,
MaxConns: params.MaxConns, MaxConns: params.MaxConns,
MaxIdleConns: params.MaxIdleConns, MaxIdleConns: params.MaxIdleConns,
Domains: domains,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -6,9 +6,10 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
) )
// 源站列表 // IndexAction 源站列表
type IndexAction struct { type IndexAction struct {
actionutils.ParentAction actionutils.ParentAction
} }
@@ -27,6 +28,33 @@ func (this *IndexAction) RunGet(params struct {
} }
serverType := serverTypeResp.Type serverType := serverTypeResp.Type
// 当前是否有分组设置
groupResp, err := this.RPC().ServerGroupRPC().FindEnabledServerGroupConfigInfo(this.AdminContext(), &pb.FindEnabledServerGroupConfigInfoRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["hasGroupConfig"] = false
this.Data["groupSettingURL"] = ""
switch serverType {
case serverconfigs.ServerTypeHTTPWeb, serverconfigs.ServerTypeHTTPProxy:
this.Data["hasGroupConfig"] = groupResp.HasHTTPReverseProxy
if groupResp.ServerGroupId > 0 {
this.Data["groupSettingURL"] = "/servers/groups/group/settings/httpReverseProxy?groupId=" + types.String(groupResp.ServerGroupId)
}
case serverconfigs.ServerTypeTCPProxy:
this.Data["hasGroupConfig"] = groupResp.HasTCPReverseProxy
if groupResp.ServerGroupId > 0 {
this.Data["groupSettingURL"] = "/servers/groups/group/settings/tcpReverseProxy?groupId=" + types.String(groupResp.ServerGroupId)
}
case serverconfigs.ServerTypeUDPProxy:
this.Data["hasGroupConfig"] = groupResp.HasUDPReverseProxy
if groupResp.ServerGroupId > 0 {
this.Data["groupSettingURL"] = "/servers/groups/group/settings/udpReverseProxy?groupId=" + types.String(groupResp.ServerGroupId)
}
}
// 当前服务的配置
reverseProxyResp, err := this.RPC().ServerRPC().FindAndInitServerReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerReverseProxyConfigRequest{ServerId: params.ServerId}) reverseProxyResp, err := this.RPC().ServerRPC().FindAndInitServerReverseProxyConfig(this.AdminContext(), &pb.FindAndInitServerReverseProxyConfigRequest{ServerId: params.ServerId})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -53,22 +81,30 @@ func (this *IndexAction) RunGet(params struct {
primaryOriginMaps := []maps.Map{} primaryOriginMaps := []maps.Map{}
backupOriginMaps := []maps.Map{} backupOriginMaps := []maps.Map{}
for _, originConfig := range reverseProxy.PrimaryOrigins { for _, originConfig := range reverseProxy.PrimaryOrigins {
if len(originConfig.Domains) == 0 {
originConfig.Domains = []string{}
}
m := maps.Map{ m := maps.Map{
"id": originConfig.Id, "id": originConfig.Id,
"weight": originConfig.Weight, "weight": originConfig.Weight,
"addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange, "addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange,
"name": originConfig.Name, "name": originConfig.Name,
"isOn": originConfig.IsOn, "isOn": originConfig.IsOn,
"domains": originConfig.Domains,
} }
primaryOriginMaps = append(primaryOriginMaps, m) primaryOriginMaps = append(primaryOriginMaps, m)
} }
for _, originConfig := range reverseProxy.BackupOrigins { for _, originConfig := range reverseProxy.BackupOrigins {
if len(originConfig.Domains) == 0 {
originConfig.Domains = []string{}
}
m := maps.Map{ m := maps.Map{
"id": originConfig.Id, "id": originConfig.Id,
"weight": originConfig.Weight, "weight": originConfig.Weight,
"addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange, "addr": originConfig.Addr.Protocol.String() + "://" + originConfig.Addr.Host + ":" + originConfig.Addr.PortRange,
"name": originConfig.Name, "name": originConfig.Name,
"isOn": originConfig.IsOn, "isOn": originConfig.IsOn,
"domains": originConfig.Domains,
} }
backupOriginMaps = append(backupOriginMaps, m) backupOriginMaps = append(backupOriginMaps, m)
} }

View File

@@ -13,7 +13,7 @@ import (
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
) )
// 修改调度算法 // UpdateSchedulingPopupAction 修改调度算法
type UpdateSchedulingPopupAction struct { type UpdateSchedulingPopupAction struct {
actionutils.ParentAction actionutils.ParentAction
} }
@@ -24,17 +24,15 @@ func (this *UpdateSchedulingPopupAction) Init() {
func (this *UpdateSchedulingPopupAction) RunGet(params struct { func (this *UpdateSchedulingPopupAction) RunGet(params struct {
Type string Type string
ServerId int64 ServerId int64
GroupId int64
ReverseProxyId int64 ReverseProxyId int64
Family string
}) { }) {
this.Data["dataType"] = params.Type this.Data["dataType"] = params.Type
this.Data["serverId"] = params.ServerId this.Data["serverId"] = params.ServerId
this.Data["groupId"] = params.GroupId
this.Data["reverseProxyId"] = params.ReverseProxyId this.Data["reverseProxyId"] = params.ReverseProxyId
_, serverConfig, isOk := serverutils.FindServer(this.Parent(), params.ServerId)
if !isOk {
return
}
reverseProxyResp, err := this.RPC().ReverseProxyRPC().FindEnabledReverseProxyConfig(this.AdminContext(), &pb.FindEnabledReverseProxyConfigRequest{ reverseProxyResp, err := this.RPC().ReverseProxyRPC().FindEnabledReverseProxyConfig(this.AdminContext(), &pb.FindEnabledReverseProxyConfigRequest{
ReverseProxyId: params.ReverseProxyId, ReverseProxyId: params.ReverseProxyId,
}) })
@@ -62,6 +60,33 @@ func (this *UpdateSchedulingPopupAction) RunGet(params struct {
// 调度类型 // 调度类型
schedulingTypes := []maps.Map{} schedulingTypes := []maps.Map{}
var isHTTPFamily = false
var isTCPFamily = false
var isUDPFamily = false
var isUnixFamily = false
if params.ServerId > 0 {
_, serverConfig, isOk := serverutils.FindServer(this.Parent(), params.ServerId)
if !isOk {
return
}
isHTTPFamily = serverConfig.IsHTTPFamily()
isTCPFamily = serverConfig.IsTCPFamily()
isUDPFamily = serverConfig.IsUDPFamily()
isUnixFamily = serverConfig.IsUnixFamily()
} else {
switch params.Family {
case "http":
isHTTPFamily = true
case "tcp":
isTCPFamily = true
case "udp":
isUDPFamily = true
case "unix":
isUnixFamily = true
}
}
for _, m := range schedulingconfigs.AllSchedulingTypes() { for _, m := range schedulingconfigs.AllSchedulingTypes() {
networks, ok := m["networks"] networks, ok := m["networks"]
if !ok { if !ok {
@@ -70,10 +95,10 @@ func (this *UpdateSchedulingPopupAction) RunGet(params struct {
if !types.IsSlice(networks) { if !types.IsSlice(networks) {
continue continue
} }
if (serverConfig.IsHTTPFamily() && lists.Contains(networks, "http")) || if (isHTTPFamily && lists.Contains(networks, "http")) ||
(serverConfig.IsTCPFamily() && lists.Contains(networks, "tcp")) || (isTCPFamily && lists.Contains(networks, "tcp")) ||
(serverConfig.IsUDPFamily() && lists.Contains(networks, "udp")) || (isUDPFamily && lists.Contains(networks, "udp")) ||
(serverConfig.IsUnixFamily() && lists.Contains(networks, "unix")) { (isUnixFamily && lists.Contains(networks, "unix")) {
schedulingTypes = append(schedulingTypes, m) schedulingTypes = append(schedulingTypes, m)
} }
} }

View File

@@ -0,0 +1,52 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package server
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
)
type ActivateAction struct {
actionutils.ParentAction
}
func (this *ActivateAction) Init() {
this.Nav("", "", "activate")
}
func (this *ActivateAction) RunGet(params struct{}) {
this.Show()
}
func (this *ActivateAction) RunPost(params struct {
Key string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
if len(params.Key) == 0 {
this.FailField("key", "请输入激活码")
}
resp, err := this.RPC().AuthorityKeyRPC().ValidateAuthorityKey(this.AdminContext(), &pb.ValidateAuthorityKeyRequest{Key: params.Key})
if err != nil {
this.ErrorPage(err)
return
}
if resp.IsOk {
_, err := this.RPC().AuthorityKeyRPC().UpdateAuthorityKey(this.AdminContext(), &pb.UpdateAuthorityKeyRequest{
Value: params.Key,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
} else {
this.FailField("key", "无法激活:"+resp.Error)
}
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
"time"
) )
type IndexAction struct { type IndexAction struct {
@@ -26,24 +27,28 @@ func (this *IndexAction) RunGet(params struct{}) {
} }
var keyMap maps.Map = nil var keyMap maps.Map = nil
teaconst.IsPlus = false teaconst.IsPlus = false
if keyResp.AuthorityKey != nil { var key = keyResp.AuthorityKey
if len(keyResp.AuthorityKey.MacAddresses) == 0 { if key != nil {
keyResp.AuthorityKey.MacAddresses = []string{} if len(key.MacAddresses) == 0 {
key.MacAddresses = []string{}
} }
isActive := len(keyResp.AuthorityKey.DayTo) > 0 && keyResp.AuthorityKey.DayTo >= timeutil.Format("Y-m-d") isActive := len(key.DayTo) > 0 && key.DayTo >= timeutil.Format("Y-m-d")
if isActive { if isActive {
teaconst.IsPlus = true teaconst.IsPlus = true
} }
isExpiring := isActive && key.DayTo < timeutil.Format("Y-m-d", time.Now().AddDate(0, 0, 7))
keyMap = maps.Map{ keyMap = maps.Map{
"dayFrom": keyResp.AuthorityKey.DayFrom, "dayFrom": key.DayFrom,
"dayTo": keyResp.AuthorityKey.DayTo, "dayTo": key.DayTo,
"macAddresses": keyResp.AuthorityKey.MacAddresses, "macAddresses": key.MacAddresses,
"hostname": keyResp.AuthorityKey.Hostname, "hostname": key.Hostname,
"company": keyResp.AuthorityKey.Company, "company": key.Company,
"nodes": keyResp.AuthorityKey.Nodes, "nodes": key.Nodes,
"isExpired": !isActive, "isExpired": !isActive,
"isExpiring": isExpiring,
"updatedTime": timeutil.FormatTime("Y-m-d H:i:s", keyResp.AuthorityKey.UpdatedAt), "updatedTime": timeutil.FormatTime("Y-m-d H:i:s", keyResp.AuthorityKey.UpdatedAt),
} }
} }

View File

@@ -14,6 +14,7 @@ func init() {
Helper(settingutils.NewAdvancedHelper("authority")). Helper(settingutils.NewAdvancedHelper("authority")).
Prefix("/settings/authority"). Prefix("/settings/authority").
Get("", new(IndexAction)). Get("", new(IndexAction)).
GetPost("/activate", new(ActivateAction)).
EndAll() EndAll()
}) })
} }

View File

@@ -39,7 +39,7 @@ func (this *AdvancedHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNex
tabbar.Add("监控节点", "", "/settings/monitorNodes", "", this.tab == "monitorNodes") tabbar.Add("监控节点", "", "/settings/monitorNodes", "", this.tab == "monitorNodes")
} }
if teaconst.BuildPlus { if teaconst.BuildPlus {
tabbar.Add("业版认证", "", "/settings/authority", "", this.tab == "authority") tabbar.Add("业版认证", "", "/settings/authority", "", this.tab == "authority")
} }
//tabbar.Add("备份", "", "/settings/backup", "", this.tab == "backup") //tabbar.Add("备份", "", "/settings/backup", "", this.tab == "backup")

View File

@@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds/condutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds/condutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
@@ -102,6 +103,26 @@ func (this *ComponentsAction) RunGet(params struct{}) {
buffer.Write([]byte{'\n', '\n'}) buffer.Write([]byte{'\n', '\n'})
} }
// IP地址阈值项目
ipAddrThresholdItemsJSON, err := json.Marshal(nodeconfigs.FindAllIPAddressThresholdItems())
if err != nil {
logs.Println("ComponentsAction marshal ip addr threshold items failed: " + err.Error())
} else {
buffer.WriteString("window.IP_ADDR_THRESHOLD_ITEMS = ")
buffer.Write(ipAddrThresholdItemsJSON)
buffer.Write([]byte{'\n', '\n'})
}
// IP地址阈值动作
ipAddrThresholdActionsJSON, err := json.Marshal(nodeconfigs.FindAllIPAddressThresholdActions())
if err != nil {
logs.Println("ComponentsAction marshal ip addr threshold actions failed: " + err.Error())
} else {
buffer.WriteString("window.IP_ADDR_THRESHOLD_ACTIONS = ")
buffer.Write(ipAddrThresholdActionsJSON)
buffer.Write([]byte{'\n', '\n'})
}
componentsData = buffer.Bytes() componentsData = buffer.Bytes()
// ETag // ETag

View File

@@ -30,6 +30,7 @@ func init() {
Post("/showTip", new(ShowTipAction)). Post("/showTip", new(ShowTipAction)).
Post("/hideTip", new(HideTipAction)). Post("/hideTip", new(HideTipAction)).
Post("/theme", new(ThemeAction)). Post("/theme", new(ThemeAction)).
Post("/validateIPs", new(ValidateIPsAction)).
EndAll() EndAll()
}) })

View File

@@ -0,0 +1,41 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ui
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"net"
"strings"
)
type ValidateIPsAction struct {
actionutils.ParentAction
}
func (this *ValidateIPsAction) RunPost(params struct {
Ips string
}) {
var ips = params.Ips
if len(ips) == 0 {
this.Data["ips"] = []string{}
this.Success()
}
var ipSlice = strings.Split(ips, "\n")
var result = []string{}
for _, ip := range ipSlice {
ip = strings.TrimSpace(ip)
if len(ip) == 0 {
continue
}
data := net.ParseIP(ip)
if len(data) == 0 {
this.Data["failIP"] = ip
this.Fail()
}
result = append(result, ip)
}
this.Data["ips"] = result
this.Success()
}

View File

@@ -180,6 +180,11 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
"subtitle": "服务列表", "subtitle": "服务列表",
"icon": "clone outsize", "icon": "clone outsize",
"subItems": []maps.Map{ "subItems": []maps.Map{
{
"name": "服务分组",
"url": "/servers/groups",
"code": "group",
},
{ {
"name": "证书管理", "name": "证书管理",
"url": "/servers/certs", "url": "/servers/certs",
@@ -216,11 +221,6 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
"url": "/servers/metrics", "url": "/servers/metrics",
"code": "metric", "code": "metric",
}, },
{
"name": "服务分组",
"url": "/servers/components/groups",
"code": "group",
},
{ {
"name": "通用设置", "name": "通用设置",
"url": "/servers/components", "url": "/servers/components",
@@ -246,12 +246,12 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
"code": "ipAddr", "code": "ipAddr",
"isOn": teaconst.IsPlus, "isOn": teaconst.IsPlus,
}, },
/**{ {
"name": "区域监控", "name": "区域监控",
"url": "/clusters/monitors", "url": "/clusters/monitors",
"code": "monitor", "code": "monitor",
"isOn": teaconst.IsPlus, "isOn": teaconst.IsPlus,
},**/ },
{ {
"name": "SSH认证", "name": "SSH认证",
"url": "/clusters/grants", "url": "/clusters/grants",

View File

@@ -41,9 +41,13 @@ import (
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/groups"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/log" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/log"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/waf" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/waf"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/settings/httpReverseProxy"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/settings/index"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/settings/tcpReverseProxy"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/groups/group/settings/udpReverseProxy"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/logs" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/logs"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/metrics" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/metrics"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/metrics/charts" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/metrics/charts"

View File

@@ -19,7 +19,13 @@ Vue.component("node-clusters-labels", {
} }
}, },
template: `<div> template: `<div>
<a v-if="cluster != null" :href="'/clusters/cluster?clusterId=' + cluster.id" class="ui label basic grey" :class="labelSize" title="主集群" style="margin-bottom: 0.3em;">{{cluster.name}}</a> <a v-if="cluster != null" :href="'/clusters/cluster?clusterId=' + cluster.id" title="主集群" style="margin-bottom: 0.3em;">
<a v-for="c in secondaryClusters" :href="'/clusters/cluster?clusterId=' + c.id" class="ui label basic grey" :class="labelSize" title="从集群" style="margin-bottom: 0.3em;"><span class="grey" style="text-decoration: none">{{c.name}}</span></a> <span class="ui label basic grey" :class="labelSize" v-if="labelSize != 'tiny'">{{cluster.name}}</span>
<grey-label v-if="labelSize == 'tiny'">{{cluster.name}}</grey-label>
</a>
<a v-for="c in secondaryClusters" :href="'/clusters/cluster?clusterId=' + c.id" :class="labelSize" title="从集群">
<span class="ui label basic grey" :class="labelSize" v-if="labelSize != 'tiny'">{{c.name}}</span>
<grey-label v-if="labelSize == 'tiny'">{{c.name}}</grey-label>
</a>
</div>` </div>`
}) })

View File

@@ -1,150 +1,150 @@
Vue.component("datetime-input", { Vue.component("datetime-input", {
props: ["v-name", "v-timestamp"], props: ["v-name", "v-timestamp"],
mounted: function () { mounted: function () {
let that = this let that = this
teaweb.datepicker(this.$refs.dayInput, function (v) { teaweb.datepicker(this.$refs.dayInput, function (v) {
that.day = v that.day = v
that.hour = "23" that.hour = "23"
that.minute = "59" that.minute = "59"
that.second = "59" that.second = "59"
that.change() that.change()
}) })
}, },
data: function () { data: function () {
let timestamp = this.vTimestamp let timestamp = this.vTimestamp
if (timestamp != null) { if (timestamp != null) {
timestamp = parseInt(timestamp) timestamp = parseInt(timestamp)
if (isNaN(timestamp)) { if (isNaN(timestamp)) {
timestamp = 0 timestamp = 0
} }
} else { } else {
timestamp = 0 timestamp = 0
} }
let day = "" let day = ""
let hour = "" let hour = ""
let minute = "" let minute = ""
let second = "" let second = ""
if (timestamp > 0) { if (timestamp > 0) {
let date = new Date() let date = new Date()
date.setTime(timestamp * 1000) date.setTime(timestamp * 1000)
let year = date.getFullYear().toString() let year = date.getFullYear().toString()
let month = this.leadingZero((date.getMonth() + 1).toString(), 2) let month = this.leadingZero((date.getMonth() + 1).toString(), 2)
day = year + "-" + month + "-" + this.leadingZero(date.getDate().toString(), 2) day = year + "-" + month + "-" + this.leadingZero(date.getDate().toString(), 2)
hour = this.leadingZero(date.getHours().toString(), 2) hour = this.leadingZero(date.getHours().toString(), 2)
minute = this.leadingZero(date.getMinutes().toString(), 2) minute = this.leadingZero(date.getMinutes().toString(), 2)
second = this.leadingZero(date.getSeconds().toString(), 2) second = this.leadingZero(date.getSeconds().toString(), 2)
} }
return { return {
timestamp: timestamp, timestamp: timestamp,
day: day, day: day,
hour: hour, hour: hour,
minute: minute, minute: minute,
second: second, second: second,
hasDayError: false, hasDayError: false,
hasHourError: false, hasHourError: false,
hasMinuteError: false, hasMinuteError: false,
hasSecondError: false hasSecondError: false
} }
}, },
methods: { methods: {
change: function () { change: function () {
let date = new Date() let date = new Date()
// day // day
if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(this.day)) { if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(this.day)) {
this.hasDayError = true this.hasDayError = true
return return
} }
let pieces = this.day.split("-") let pieces = this.day.split("-")
let year = parseInt(pieces[0]) let year = parseInt(pieces[0])
date.setFullYear(year) date.setFullYear(year)
let month = parseInt(pieces[1]) let month = parseInt(pieces[1])
if (month < 1 || month > 12) { if (month < 1 || month > 12) {
this.hasDayError = true this.hasDayError = true
return return
} }
date.setMonth(month - 1) date.setMonth(month - 1)
let day = parseInt(pieces[2]) let day = parseInt(pieces[2])
if (day < 1 || day > 32) { if (day < 1 || day > 32) {
this.hasDayError = true this.hasDayError = true
return return
} }
date.setDate(day) date.setDate(day)
this.hasDayError = false this.hasDayError = false
// hour // hour
if (!/^\d+$/.test(this.hour)) { if (!/^\d+$/.test(this.hour)) {
this.hasHourError = true this.hasHourError = true
return return
} }
let hour = parseInt(this.hour) let hour = parseInt(this.hour)
if (isNaN(hour)) { if (isNaN(hour)) {
this.hasHourError = true this.hasHourError = true
return return
} }
if (hour < 0 || hour >= 24) { if (hour < 0 || hour >= 24) {
this.hasHourError = true this.hasHourError = true
return return
} }
this.hasHourError = false this.hasHourError = false
date.setHours(hour) date.setHours(hour)
// minute // minute
if (!/^\d+$/.test(this.minute)) { if (!/^\d+$/.test(this.minute)) {
this.hasMinuteError = true this.hasMinuteError = true
return return
} }
let minute = parseInt(this.minute) let minute = parseInt(this.minute)
if (isNaN(minute)) { if (isNaN(minute)) {
this.hasMinuteError = true this.hasMinuteError = true
return return
} }
if (minute < 0 || minute >= 60) { if (minute < 0 || minute >= 60) {
this.hasMinuteError = true this.hasMinuteError = true
return return
} }
this.hasMinuteError = false this.hasMinuteError = false
date.setMinutes(minute) date.setMinutes(minute)
// second // second
if (!/^\d+$/.test(this.second)) { if (!/^\d+$/.test(this.second)) {
this.hasSecondError = true this.hasSecondError = true
return return
} }
let second = parseInt(this.second) let second = parseInt(this.second)
if (isNaN(second)) { if (isNaN(second)) {
this.hasSecondError = true this.hasSecondError = true
return return
} }
if (second < 0 || second >= 60) { if (second < 0 || second >= 60) {
this.hasSecondError = true this.hasSecondError = true
return return
} }
this.hasSecondError = false this.hasSecondError = false
date.setSeconds(second) date.setSeconds(second)
this.timestamp = parseInt(date.getTime() / 1000) this.timestamp = Math.ceil(date.getTime() / 1000)
}, },
leadingZero: function (s, l) { leadingZero: function (s, l) {
if (l <= s.length) { if (l <= s.length) {
return s return s
} }
for (let i = 0; i < l - s.length; i++) { for (let i = 0; i < l - s.length; i++) {
s = "0" + s s = "0" + s
} }
return s return s
} }
}, },
template: `<div> template: `<div>
<input type="hidden" :name="vName" :value="timestamp"/> <input type="hidden" :name="vName" :value="timestamp"/>
<div class="ui fields inline" style="padding: 0; margin:0"> <div class="ui fields inline" style="padding: 0; margin:0">
<div class="ui field" :class="{error: hasDayError}"> <div class="ui field" :class="{error: hasDayError}">

View File

@@ -6,7 +6,12 @@ Vue.component("label-on", {
// 文字代码标签 // 文字代码标签
Vue.component("code-label", { Vue.component("code-label", {
template: `<span class="ui label basic tiny" style="padding: 3px;margin-left:2px;margin-right:2px"><slot></slot></span>` methods: {
click: function (args) {
this.$emit("click", args)
}
},
template: `<span class="ui label basic tiny" style="padding: 3px;margin-left:2px;margin-right:2px" @click.prevent="click"><slot></slot></span>`
}) })
// tiny标签 // tiny标签
@@ -26,5 +31,5 @@ Vue.component("micro-basic-label", {
// 灰色的Label // 灰色的Label
Vue.component("grey-label", { Vue.component("grey-label", {
template: `<span class="grey small"><slot></slot></span>` template: `<span class="ui label basic grey tiny" style="margin-top: 0.4em; font-size: 0.7em; border: 1px solid #ddd!important; font-weight: normal;"><slot></slot></span>`
}) })

View File

@@ -1,12 +1,12 @@
// 使用Icon的链接方式 // 使用Icon的链接方式
Vue.component("link-icon", { Vue.component("link-icon", {
props: ["href", "title"], props: ["href", "title", "target"],
data: function () { data: function () {
return { return {
vTitle: (this.title == null) ? "打开链接" : this.title vTitle: (this.title == null) ? "打开链接" : this.title
} }
}, },
template: `<span><slot></slot>&nbsp;<a :href="href" :title="vTitle" class="link grey"><i class="icon linkify small"></i></a></span>` template: `<span><slot></slot>&nbsp;<a :href="href" :title="vTitle" class="link grey" :target="target"><i class="icon linkify small"></i></a></span>`
}) })
// 带有下划虚线的连接 // 带有下划虚线的连接

View File

@@ -66,7 +66,7 @@ Vue.component("network-addresses-box", {
updateAddr: function (index, addr) { updateAddr: function (index, addr) {
let that = this let that = this
window.UPDATING_ADDR = addr window.UPDATING_ADDR = addr
teaweb.popup("/servers/addPortPopup?serverType=" + this.vServerType + "&protocol=" + this.protocol, { teaweb.popup("/servers/addPortPopup?serverType=" + this.vServerType + "&protocol=" + this.protocol + "&from=" + this.from, {
height: "16em", height: "16em",
callback: function (resp) { callback: function (resp) {
var addr = resp.data.address var addr = resp.data.address

View File

@@ -55,6 +55,9 @@ Vue.component("values-box", {
}, },
updateAll: function (values) { updateAll: function (values) {
this.vValeus = values this.vValeus = values
},
addValue: function (v) {
this.vValues.push(v)
} }
}, },
template: `<div> template: `<div>

View File

@@ -5,6 +5,12 @@ Vue.component("dns-route-selector", {
if (routes == null) { if (routes == null) {
routes = [] routes = []
} }
routes.$sort(function (v1, v2) {
if (v1.domainId == v2.domainId) {
return v1.code < v2.code
}
return (v1.domainId < v2.domainId) ? 1 : -1
})
return { return {
routes: routes, routes: routes,
routeCodes: routes.$map(function (k, v) { routeCodes: routes.$map(function (k, v) {
@@ -49,6 +55,13 @@ Vue.component("dns-route-selector", {
this.routeCodes.push(this.routeCode) this.routeCodes.push(this.routeCode)
this.routes.push(route) this.routes.push(route)
this.routes.$sort(function (v1, v2) {
if (v1.domainId == v2.domainId) {
return v1.code < v2.code
}
return (v1.domainId < v2.domainId) ? 1 : -1
})
this.routeCode = "" this.routeCode = ""
this.isAdding = false this.isAdding = false
}, },

View File

@@ -1,41 +1,51 @@
Vue.component("message-row", { Vue.component("message-row", {
props: ["v-message"], props: ["v-message", "v-can-close"],
data: function () { data: function () {
let paramsJSON = this.vMessage.params let paramsJSON = this.vMessage.params
let params = null let params = null
if (paramsJSON != null && paramsJSON.length > 0) { if (paramsJSON != null && paramsJSON.length > 0) {
params = JSON.parse(paramsJSON) params = JSON.parse(paramsJSON)
} }
return { return {
message: this.vMessage, message: this.vMessage,
params: params params: params,
} isClosing: false
}, }
methods: { },
viewCert: function (certId) { methods: {
teaweb.popup("/servers/certs/certPopup?certId=" + certId, { viewCert: function (certId) {
height: "28em", teaweb.popup("/servers/certs/certPopup?certId=" + certId, {
width: "48em" height: "28em",
}) width: "48em"
}, })
readMessage: function (messageId) { },
Tea.action("/messages/readPage") readMessage: function (messageId) {
.params({"messageIds": [messageId]}) let that = this
.post()
.success(function () {
// 刷新父级页面Badge
if (window.parent.Tea != null && window.parent.Tea.Vue != null) {
window.parent.Tea.Vue.checkMessagesOnce()
}
// 刷新当前页面 Tea.action("/messages/readPage")
teaweb.reload() .params({"messageIds": [messageId]})
}) .post()
} .success(function () {
}, // 刷新父级页面Badge
template: `<div> if (window.parent.Tea != null && window.parent.Tea.Vue != null) {
<table class="ui table selectable"> window.parent.Tea.Vue.checkMessagesOnce()
}
// 刷新当前页面
if (that.vCanClose && typeof (NotifyPopup) != "undefined") {
that.isClosing = true
setTimeout(function () {
NotifyPopup({})
}, 1000)
} else {
teaweb.reload()
}
})
}
},
template: `<div>
<table class="ui table selectable" v-if="!isClosing">
<tr :class="{error: message.level == 'error', positive: message.level == 'success', warning: message.level == 'warning'}"> <tr :class="{error: message.level == 'error', positive: message.level == 'success', warning: message.level == 'warning'}">
<td style="position: relative"> <td style="position: relative">
<strong>{{message.datetime}}</strong> <strong>{{message.datetime}}</strong>

View File

@@ -5,209 +5,494 @@ Vue.component("node-ip-address-thresholds-box", {
let thresholds = this.vThresholds let thresholds = this.vThresholds
if (thresholds == null) { if (thresholds == null) {
thresholds = [] thresholds = []
} else {
thresholds.forEach(function (v) {
if (v.items == null) {
v.items = []
}
if (v.actions == null) {
v.actions = []
}
})
} }
let avgRequests = {
duration: "",
operator: "lte",
value: ""
}
let avgTrafficOut = {
duration: "",
operator: "lte",
value: ""
}
let avgTrafficIn = {
duration: "",
operator: "lte",
value: ""
}
thresholds.forEach(function (v) {
switch (v.item) {
case "avgRequests":
avgRequests.duration = v.duration
avgRequests.operator = v.operator
avgRequests.value = v.value.toString()
break
case "avgTrafficOut":
avgTrafficOut.duration = v.duration
avgTrafficOut.operator = v.operator
avgTrafficOut.value = v.value.toString()
break
case "avgTrafficIn":
avgTrafficIn.duration = v.duration
avgTrafficIn.operator = v.operator
avgTrafficIn.value = v.value.toString()
break
}
})
return { return {
editingIndex: -1,
thresholds: thresholds, thresholds: thresholds,
avgRequests: avgRequests, addingThreshold: {
avgTrafficOut: avgTrafficOut, items: [],
avgTrafficIn: avgTrafficIn actions: []
} },
}, isAdding: false,
watch: { isAddingItem: false,
"avgRequests.duration": function () { isAddingAction: false,
this.compose()
}, itemCode: "nodeAvgRequests",
"avgRequests.operator": function () { itemReportGroups: [],
this.compose() itemOperator: "lte",
}, itemValue: "",
"avgRequests.value": function () { itemDuration: "5",
this.compose() allItems: window.IP_ADDR_THRESHOLD_ITEMS,
}, allOperators: [
"avgTrafficOut.duration": function () { {
this.compose() "name": "小于等于",
}, "code": "lte"
"avgTrafficOut.operator": function () { },
this.compose() {
}, "name": "大于",
"avgTrafficOut.value": function () { "code": "gt"
this.compose() },
}, {
"avgTrafficIn.duration": function () { "name": "不等于",
this.compose() "code": "neq"
}, },
"avgTrafficIn.operator": function () { {
this.compose() "name": "小于",
}, "code": "lt"
"avgTrafficIn.value": function () { },
this.compose() {
"name": "大于等于",
"code": "gte"
}
],
allActions: window.IP_ADDR_THRESHOLD_ACTIONS,
actionCode: "up",
actionBackupIPs: "",
actionWebHookURL: ""
} }
}, },
methods: { methods: {
compose: function () { add: function () {
let thresholds = [] this.isAdding = !this.isAdding
},
// avg requests cancel: function () {
{ this.isAdding = false
let duration = parseInt(this.avgRequests.duration) this.editingIndex = -1
let value = parseInt(this.avgRequests.value) this.addingThreshold = {
if (!isNaN(duration) && duration > 0 && !isNaN(value) && value > 0) { items: [],
thresholds.push({ actions: []
item: "avgRequests", }
operator: this.avgRequests.operator, },
duration: duration, confirm: function () {
durationUnit: "minute", if (this.addingThreshold.items.length == 0) {
value: value teaweb.warn("需要至少添加一个阈值")
}) return
} }
if (this.addingThreshold.actions.length == 0) {
teaweb.warn("需要至少添加一个动作")
return
} }
// avg traffic out if (this.editingIndex >= 0) {
{ this.thresholds[this.editingIndex].items = this.addingThreshold.items
let duration = parseInt(this.avgTrafficOut.duration) this.thresholds[this.editingIndex].actions = this.addingThreshold.actions
let value = parseInt(this.avgTrafficOut.value) } else {
if (!isNaN(duration) && duration > 0 && !isNaN(value) && value > 0) { this.thresholds.push({
thresholds.push({ items: this.addingThreshold.items,
item: "avgTrafficOut", actions: this.addingThreshold.actions
operator: this.avgTrafficOut.operator, })
duration: duration,
durationUnit: "minute",
value: value
})
}
} }
// avg requests // 还原
{ this.cancel()
let duration = parseInt(this.avgTrafficIn.duration) },
let value = parseInt(this.avgTrafficIn.value) remove: function (index) {
if (!isNaN(duration) && duration > 0 && !isNaN(value) && value > 0) { this.cancel()
thresholds.push({ this.thresholds.$remove(index)
item: "avgTrafficIn", },
operator: this.avgTrafficIn.operator, update: function (index) {
duration: duration, this.editingIndex = index
durationUnit: "minute", this.addingThreshold = {
value: value items: this.thresholds[index].items.$copy(),
}) actions: this.thresholds[index].actions.$copy()
} }
this.isAdding = true
},
addItem: function () {
this.isAddingItem = !this.isAddingItem
let that = this
setTimeout(function () {
that.$refs.itemValue.focus()
}, 100)
},
cancelItem: function () {
this.isAddingItem = false
this.itemCode = "nodeAvgRequests"
this.itmeOperator = "lte"
this.itemValue = ""
this.itemDuration = "5"
this.itemReportGroups = []
},
confirmItem: function () {
if (this.itemDuration.length == 0) {
let that = this
teaweb.warn("请输入统计周期", function () {
that.$refs.itemDuration.focus()
})
return
}
let itemDuration = parseInt(this.itemDuration)
if (isNaN(itemDuration) || itemDuration <= 0) {
teaweb.warn("请输入正确的统计周期", function () {
that.$refs.itemDuration.focus()
})
return
} }
this.thresholds = thresholds if (this.itemValue.length == 0) {
let that = this
teaweb.warn("请输入对比值", function () {
that.$refs.itemValue.focus()
})
return
}
let itemValue = parseFloat(this.itemValue)
if (isNaN(itemValue)) {
teaweb.warn("请输入正确的对比值", function () {
that.$refs.itemValue.focus()
})
return
}
let options = {}
switch (this.itemCode) {
case "connectivity": // 连通性校验
if (itemValue > 100) {
let that = this
teaweb.warn("连通性对比值不能超过100", function () {
that.$refs.itemValue.focus()
})
return
}
options["groups"] = this.itemReportGroups
break
}
// 添加
this.addingThreshold.items.push({
item: this.itemCode,
operator: this.itemOperator,
value: itemValue,
duration: itemDuration,
durationUnit: "minute",
options: options
})
// 还原
this.cancelItem()
},
removeItem: function (index) {
this.cancelItem()
this.addingThreshold.items.$remove(index)
},
changeReportGroups: function (groups) {
this.itemReportGroups = groups
},
itemName: function (item) {
let result = ""
this.allItems.forEach(function (v) {
if (v.code == item) {
result = v.name
}
})
return result
},
itemUnitName: function (itemCode) {
let result = ""
this.allItems.forEach(function (v) {
if (v.code == itemCode) {
result = v.unit
}
})
return result
},
itemDurationUnitName: function (unit) {
switch (unit) {
case "minute":
return "分钟"
case "second":
return "秒"
case "hour":
return "小时"
case "day":
return "天"
}
return unit
},
itemOperatorName: function (operator) {
let result = ""
this.allOperators.forEach(function (v) {
if (v.code == operator) {
result = v.name
}
})
return result
},
addAction: function () {
this.isAddingAction = !this.isAddingAction
},
cancelAction: function () {
this.isAddingAction = false
this.actionCode = "up"
this.actionBackupIPs = ""
this.actionWebHookURL = ""
},
confirmAction: function () {
this.doConfirmAction(false)
},
doConfirmAction: function (validated, options) {
// 是否已存在
let exists = false
let that = this
this.addingThreshold.actions.forEach(function (v) {
if (v.action == that.actionCode) {
exists = true
}
})
if (exists) {
teaweb.warn("此动作已经添加过了,无需重复添加")
return
}
if (options == null) {
options = {}
}
switch (this.actionCode) {
case "switch":
if (!validated) {
Tea.action("/ui/validateIPs")
.params({
"ips": this.actionBackupIPs
})
.success(function (resp) {
if (resp.data.ips.length == 0) {
teaweb.warn("请输入备用IP", function () {
that.$refs.actionBackupIPs.focus()
})
return
}
options["ips"] = resp.data.ips
that.doConfirmAction(true, options)
})
.fail(function (resp) {
teaweb.warn("输入的IP '" + resp.data.failIP + "' 格式不正确,请改正后提交", function () {
that.$refs.actionBackupIPs.focus()
})
})
.post()
return
}
break
case "webHook":
if (this.actionWebHookURL.length ==0) {
teaweb.warn("请输入WebHook URL", function () {
that.$refs.webHookURL.focus()
})
return
}
if (!this.actionWebHookURL.match(/^(http|https):\/\//i)) {
teaweb.warn("URL开头必须是http://或者https://", function () {
that.$refs.webHookURL.focus()
})
return
}
options["url"] = this.actionWebHookURL
}
this.addingThreshold.actions.push({
action: this.actionCode,
options: options
})
// 还原
this.cancelAction()
},
removeAction: function (index) {
this.cancelAction()
this.addingThreshold.actions.$remove(index)
},
actionName: function (actionCode) {
let result = ""
this.allActions.forEach(function (v) {
if (v.code == actionCode) {
result = v.name
}
})
return result
} }
}, },
template: `<div> template: `<div>
<input type="hidden" name="thresholdsJSON" :value="JSON.stringify(thresholds)"/> <input type="hidden" name="thresholdsJSON" :value="JSON.stringify(thresholds)"/>
<table class="ui table celled">
<thead> <!-- 已有条件 -->
<div v-if="thresholds.length > 0">
<div class="ui label basic small" v-for="(threshold, index) in thresholds">
<span v-for="(item, itemIndex) in threshold.items">[{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] {{itemName(item.item)}}
<!-- 连通性 -->
<span v-if="item.item == 'connectivity' && item.options != null && item.options.groups != null && item.options.groups.length > 0">[<span v-for="(group, groupIndex) in item.options.groups">{{group.name}} <span v-if="groupIndex != item.options.groups.length - 1">&nbsp; </span></span>]</span>
<span class="grey">[{{itemOperatorName(item.operator)}}]</span> &nbsp;{{item.value}}{{itemUnitName(item.item)}} &nbsp;<span v-if="itemIndex != threshold.items.length - 1" style="font-style: italic">AND &nbsp;</span></span>
-&gt;
<span v-for="(action, actionIndex) in threshold.actions">{{actionName(action.action)}}
<span v-if="action.action == 'switch'">到{{action.options.ips.join(", ")}}</span>
<span v-if="action.action == 'webHook'" class="small grey">({{action.options.url}})</span>
&nbsp;<span v-if="actionIndex != threshold.actions.length - 1" style="font-style: italic">AND &nbsp;</span></span>
&nbsp;
<a href="" title="修改" @click.prevent="update(index)"><i class="icon pencil small"></i></a>
<a href="" title="删除" @click.prevent="remove(index)"><i class="icon small remove"></i></a>
</div>
</div>
<!-- 新阈值 -->
<div v-if="isAdding" style="margin-top: 0.5em">
<table class="ui table celled">
<thead>
<tr>
<td style="width: 50%; background: #f9fafb; border-bottom: 1px solid rgba(34,36,38,.1)">阈值</td>
<th>动作</th>
</tr>
</thead>
<tr> <tr>
<td>统计项目</td> <td style="background: white">
<th>统计周期</th> <!-- 已经添加的项目 -->
<th>操作符</th> <div>
<th>对比值</th> <div v-for="(item, index) in addingThreshold.items" class="ui label basic small" style="margin-bottom: 0.5em;">
</tr> [{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] {{itemName(item.item)}}
</thead> <!-- 连通性 -->
<tr> <span v-if="item.item == 'connectivity' && item.options != null && item.options.groups != null && item.options.groups.length > 0">[<span v-for="(group, groupIndex) in item.options.groups">{{group.name}} <span v-if="groupIndex != item.options.groups.length - 1">&nbsp; </span></span>]</span>
<td>平均请求数/秒</td> <span class="grey">[{{itemOperatorName(item.operator)}}]</span> {{item.value}}{{itemUnitName(item.item)}} &nbsp;
<td> <a href="" title="删除" @click.prevent="removeItem(index)"><i class="icon remove small"></i></a>
<div class="ui input right labeled"> </div>
<input type="text" style="width: 5em" v-model="avgRequests.duration"/> </div>
<span class="ui label">分钟</span>
</div> <!-- 正在添加的项目 -->
</td> <div v-if="isAddingItem" style="margin-top: 0.8em">
<td> <table class="ui table">
<select class="ui dropdown auto-width" v-model="avgRequests.operator"> <tr>
<option value="lte">小于等于</option> <td style="width: 6em">统计项目</td>
<option value="gt">大于</option> <td>
</select> <select class="ui dropdown auto-width" v-model="itemCode">
</td> <option v-for="item in allItems" :value="item.code">{{item.name}}</option>
<td> </select>
<div class="ui input right labeled"> <p class="comment" v-for="item in allItems" v-if="item.code == itemCode">{{item.description}}</p>
<input type="text" style="width: 6em" v-model="avgRequests.value"/> </td>
<span class="ui label">个</span> </tr>
</div> <tr>
</td> <td>统计周期</td>
</tr> <td>
<tr> <div class="ui input right labeled">
<td class="title">平均下行流量/秒</td> <input type="text" v-model="itemDuration" style="width: 4em" maxlength="4" ref="itemDuration" @keyup.enter="confirmItem()" @keypress.enter.prevent="1"/>
<td> <span class="ui label">分钟</span>
<div class="ui input right labeled"> </div>
<input type="text" style="width: 5em" v-model="avgTrafficOut.duration"/> </td>
<span class="ui label">分钟</span> </tr>
</div> <tr>
</td> <td>操作符</td>
<td> <td>
<select class="ui dropdown auto-width" v-model="avgTrafficOut.operator"> <select class="ui dropdown auto-width" v-model="itemOperator">
<option value="lte">小于等于</option> <option v-for="operator in allOperators" :value="operator.code">{{operator.name}}</option>
<option value="gt">大于</option> </select>
</select> </td>
</td> </tr>
<td> <tr>
<div class="ui input right labeled"> <td>对比值</td>
<input type="text" style="width: 6em" v-model="avgTrafficOut.value"/> <td>
<span class="ui label">MB</span> <div class="ui input right labeled">
</div> <input type="text" maxlength="20" style="width: 5em" v-model="itemValue" ref="itemValue" @keyup.enter="confirmItem()" @keypress.enter.prevent="1"/>
</td> <span class="ui label" v-for="item in allItems" v-if="item.code == itemCode">{{item.unit}}</span>
</tr> </div>
<tr> </td>
<td>平均上行流量/秒</td> </tr>
<td>
<div class="ui input right labeled"> <!-- 连通性 -->
<input type="text" style="width: 5em" v-model="avgTrafficIn.duration"/> <tr v-if="itemCode == 'connectivity'">
<span class="ui label">分钟</span> <td>终端分组</td>
</div> <td style="font-weight: normal">
</td> <div style="zoom: 0.8"><report-node-groups-selector @change="changeReportGroups"></report-node-groups-selector></div>
<td> </td>
<select class="ui dropdown auto-width" v-model="avgTrafficIn.operator"> </tr>
<option value="lte">小于等于</option> </table>
<option value="gt">大于</option> <div style="margin-top: 0.8em">
</select> <button class="ui button tiny" type="button" @click.prevent="confirmItem">确定</button> &nbsp;
</td> <a href="" title="取消" @click.prevent="cancelItem"><i class="icon remove small"></i></a>
<td> </div>
<div class="ui input right labeled"> </div>
<input type="text" style="width: 6em" v-model="avgTrafficIn.value"/> <div style="margin-top: 0.8em" v-if="!isAddingItem">
<span class="ui label">MB</span> <button class="ui button tiny" type="button" @click.prevent="addItem">+</button>
</div> </div>
</td> </td>
</tr> <td style="background: white">
</table> <!-- 已经添加的动作 -->
<p class="comment">满足所有阈值条件时IP才会上线否则下线。统计周期和对比值设置为0表示没有限制。各个输入项只支持整数数字。</p> <div>
<div v-for="(action, index) in addingThreshold.actions" class="ui label basic small" style="margin-bottom: 0.5em">
{{actionName(action.action)}} &nbsp;
<span v-if="action.action == 'switch'">到{{action.options.ips.join(", ")}}</span>
<span v-if="action.action == 'webHook'" class="small grey">({{action.options.url}})</span>
<a href="" title="删除" @click.prevent="removeAction(index)"><i class="icon remove small"></i></a>
</div>
</div>
<!-- 正在添加的动作 -->
<div v-if="isAddingAction" style="margin-top: 0.8em">
<table class="ui table">
<tr>
<td style="width: 6em">动作类型</td>
<td>
<select class="ui dropdown auto-width" v-model="actionCode">
<option v-for="action in allActions" :value="action.code">{{action.name}}</option>
</select>
<p class="comment" v-for="action in allActions" v-if="action.code == actionCode">{{action.description}}</p>
</td>
</tr>
<!-- 切换 -->
<tr v-if="actionCode == 'switch'">
<td>备用IP *</td>
<td>
<textarea rows="2" v-model="actionBackupIPs" ref="actionBackupIPs"></textarea>
<p class="comment">每行一个备用IP。</p>
</td>
</tr>
<!-- WebHook -->
<tr v-if="actionCode == 'webHook'">
<td>URL *</td>
<td>
<input type="text" maxlength="1000" placeholder="https://..." v-model="actionWebHookURL" ref="webHookURL" @keyup.enter="confirmAction()" @keypress.enter.prevent="1"/>
<p class="comment">完整的URL比如<code-label>https://example.com/webhook/api</code-label>系统会在触发阈值的时候通过GET调用此URL。</p>
</td>
</tr>
</table>
<div style="margin-top: 0.8em">
<button class="ui button tiny" type="button" @click.prevent="confirmAction">确定</button> &nbsp;
<a href="" title="取消" @click.prevent="cancelAction"><i class="icon remove small"></i></a>
</div>
</div>
<div style="margin-top: 0.8em" v-if="!isAddingAction">
<button class="ui button tiny" type="button" @click.prevent="addAction">+</button>
</div>
</td>
</tr>
</table>
<!-- 添加阈值 -->
<div>
<button class="ui button tiny" :class="{disabled: (isAddingItem || isAddingAction)}" type="button" @click.prevent="confirm">确定</button> &nbsp;
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
</div>
</div>
<div v-if="!isAdding" style="margin-top: 0.5em">
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
</div>
</div>` </div>`
}) })

View File

@@ -0,0 +1,115 @@
// 节点IP阈值
Vue.component("node-ip-address-thresholds-view", {
props: ["v-thresholds"],
data: function () {
let thresholds = this.vThresholds
if (thresholds == null) {
thresholds = []
} else {
thresholds.forEach(function (v) {
if (v.items == null) {
v.items = []
}
if (v.actions == null) {
v.actions = []
}
})
}
return {
thresholds: thresholds,
allItems: window.IP_ADDR_THRESHOLD_ITEMS,
allOperators: [
{
"name": "小于等于",
"code": "lte"
},
{
"name": "大于",
"code": "gt"
},
{
"name": "不等于",
"code": "neq"
},
{
"name": "小于",
"code": "lt"
},
{
"name": "大于等于",
"code": "gte"
}
],
allActions: window.IP_ADDR_THRESHOLD_ACTIONS
}
},
methods: {
itemName: function (item) {
let result = ""
this.allItems.forEach(function (v) {
if (v.code == item) {
result = v.name
}
})
return result
},
itemUnitName: function (itemCode) {
let result = ""
this.allItems.forEach(function (v) {
if (v.code == itemCode) {
result = v.unit
}
})
return result
},
itemDurationUnitName: function (unit) {
switch (unit) {
case "minute":
return "分钟"
case "second":
return "秒"
case "hour":
return "小时"
case "day":
return "天"
}
return unit
},
itemOperatorName: function (operator) {
let result = ""
this.allOperators.forEach(function (v) {
if (v.code == operator) {
result = v.name
}
})
return result
},
actionName: function (actionCode) {
let result = ""
this.allActions.forEach(function (v) {
if (v.code == actionCode) {
result = v.name
}
})
return result
}
},
template: `<div>
<!-- 已有条件 -->
<div v-if="thresholds.length > 0">
<div class="ui label basic small" v-for="(threshold, index) in thresholds" style="margin-bottom: 0.5em">
<span v-for="(item, itemIndex) in threshold.items">[{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] {{itemName(item.item)}}
<!-- 连通性 -->
<span v-if="item.item == 'connectivity' && item.options != null && item.options.groups != null && item.options.groups.length > 0">[<span v-for="(group, groupIndex) in item.options.groups">{{group.name}} <span v-if="groupIndex != item.options.groups.length - 1">&nbsp; </span></span>]</span>
<span class="grey">[{{itemOperatorName(item.operator)}}]</span> {{item.value}}{{itemUnitName(item.item)}} &nbsp;<span v-if="itemIndex != threshold.items.length - 1" style="font-style: italic">AND &nbsp;</span></span>
-&gt;
<span v-for="(action, actionIndex) in threshold.actions">{{actionName(action.action)}}
<span v-if="action.action == 'switch'">到{{action.options.ips.join(", ")}}</span>
<span v-if="action.action == 'webHook'" class="small grey">({{action.options.url}})</span>
&nbsp;<span v-if="actionIndex != threshold.actions.length - 1" style="font-style: italic">AND &nbsp;</span></span>
</div>
</div>
</div>`
})

View File

@@ -56,7 +56,7 @@ Vue.component("node-ip-addresses-box", {
<span class="small grey" v-if="address.name.length == 0 && !address.canAccess">(不可访问)</span> <span class="small grey" v-if="address.name.length == 0 && !address.canAccess">(不可访问)</span>
<span class="small red" v-if="!address.isOn" title="未启用">[off]</span> <span class="small red" v-if="!address.isOn" title="未启用">[off]</span>
<span class="small red" v-if="!address.isUp" title="已下线">[down]</span> <span class="small red" v-if="!address.isUp" title="已下线">[down]</span>
<span class="small" v-if="address.thresholds != null && address.thresholds.length > 0">[阈值]</span> <span class="small" v-if="address.thresholds != null && address.thresholds.length > 0">[{{address.thresholds.length}}个阈值]</span>
&nbsp; &nbsp;
<a href="" title="修改" @click.prevent="updateIPAddress(index, address)"><i class="icon pencil small"></i></a> <a href="" title="修改" @click.prevent="updateIPAddress(index, address)"><i class="icon pencil small"></i></a>
<a href="" title="删除" @click.prevent="removeIPAddress(index)"><i class="icon remove"></i></a> <a href="" title="删除" @click.prevent="removeIPAddress(index)"><i class="icon remove"></i></a>

View File

@@ -0,0 +1,92 @@
// 监控节点分组选择
Vue.component("report-node-groups-selector", {
props: ["v-group-ids"],
mounted: function () {
let that = this
Tea.action("/clusters/monitors/groups/options")
.post()
.success(function (resp) {
that.groups = resp.data.groups.map(function (group) {
group.isChecked = that.groupIds.$contains(group.id)
return group
})
that.isLoaded = true
})
},
data: function () {
var groupIds = this.vGroupIds
if (groupIds == null) {
groupIds = []
}
return {
groups: [],
groupIds: groupIds,
isLoaded: false,
allGroups: groupIds.length == 0
}
},
methods: {
check: function (group) {
group.isChecked = !group.isChecked
this.groupIds = []
let that = this
this.groups.forEach(function (v) {
if (v.isChecked) {
that.groupIds.push(v.id)
}
})
this.change()
},
change: function () {
let that = this
let groups = []
this.groupIds.forEach(function (groupId) {
let group = that.groups.$find(function (k, v) {
return v.id == groupId
})
if (group == null) {
return
}
groups.push({
id: group.id,
name: group.name
})
})
this.$emit("change", groups)
}
},
watch: {
allGroups: function (b) {
if (b) {
this.groupIds = []
this.groups.forEach(function (v) {
v.isChecked = false
})
}
this.change()
}
},
template: `<div>
<input type="hidden" name="reportNodeGroupIdsJSON" :value="JSON.stringify(groupIds)"/>
<span class="disabled" v-if="isLoaded && groups.length == 0">还没有分组。</span>
<div v-if="groups.length > 0">
<div>
<div class="ui checkbox">
<input type="checkbox" v-model="allGroups" id="all-group"/>
<label for="all-group">全部分组</label>
</div>
<div class="ui divider" v-if="!allGroups"></div>
</div>
<div v-show="!allGroups">
<div v-for="group in groups" :key="group.id" style="float: left; width: 7.6em; margin-bottom: 0.5em">
<div class="ui checkbox">
<input type="checkbox" v-model="group.isChecked" value="1" :id="'report-node-group-' + group.id" @click.prevent="check(group)"/>
<label :for="'report-node-group-' + group.id">{{group.name}}</label>
</div>
</div>
</div>
</div>
</div>`
})

View File

@@ -0,0 +1,90 @@
// 域名列表
Vue.component("domains-box", {
props: ["v-domains"],
data: function () {
let domains = this.vDomains
if (domains == null) {
domains = []
}
return {
domains: domains,
isAdding: false,
addingDomain: ""
}
},
methods: {
add: function () {
this.isAdding = true
let that = this
setTimeout(function () {
that.$refs.addingDomain.focus()
}, 100)
},
confirm: function () {
let that = this
// 删除其中的空格
this.addingDomain = this.addingDomain.replace(/\s/g, "")
if (this.addingDomain.length == 0) {
teaweb.warn("请输入要添加的域名", function () {
that.$refs.addingDomain.focus()
})
return
}
// 基本校验
if (this.addingDomain[0] == "~") {
let expr = this.addingDomain.substring(1)
try {
new RegExp(expr)
} catch (e) {
teaweb.warn("正则表达式错误:" + e.message, function () {
that.$refs.addingDomain.focus()
})
return
}
}
this.domains.push(this.addingDomain)
this.cancel()
},
remove: function (index) {
this.domains.$remove(index)
},
cancel: function () {
this.isAdding = false
this.addingDomain = ""
}
},
template: `<div>
<input type="hidden" name="domainsJSON" :value="JSON.stringify(domains)"/>
<div v-if="domains.length > 0">
<span class="ui label small basic" v-for="(domain, index) in domains">
<span v-if="domain.length > 0 && domain[0] == '~'" class="grey" style="font-style: normal">[正则]</span>
<span v-if="domain.length > 0 && domain[0] == '.'" class="grey" style="font-style: normal">[后缀]</span>
<span v-if="domain.length > 0 && domain[0] == '*'" class="grey" style="font-style: normal">[泛域名]</span>
{{domain}}
&nbsp; <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
</span>
<div class="ui divider"></div>
</div>
<div v-if="isAdding">
<div class="ui fields">
<div class="ui field">
<input type="text" v-model="addingDomain" @keyup.enter="confirm()" @keypress.enter.prevent="1" ref="addingDomain" placeholder="*.xxx.com" size="30"/>
</div>
<div class="ui field">
<button class="ui button tiny" type="button" @click.prevent="confirm">确定</button>
&nbsp; <a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
</div>
</div>
<p class="comment">支持普通域名(<code-label>example.com</code-label>)、泛域名(<code-label>*.example.com</code-label>)、域名后缀(以点号开头,如<code-label>.example.com</code-label>)和正则表达式(以波浪号开头,如<code-label>~.*.example.com</code-label>)。</p>
<div class="ui divider"></div>
</div>
<div style="margin-top: 0.5em" v-if="!isAdding">
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
</div>
</div>`
})

View File

@@ -9,7 +9,7 @@ Vue.component("origin-list-box", {
methods: { methods: {
createPrimaryOrigin: function () { createPrimaryOrigin: function () {
teaweb.popup("/servers/server/settings/origins/addPopup?originType=primary&" + this.vParams, { teaweb.popup("/servers/server/settings/origins/addPopup?originType=primary&" + this.vParams, {
height: "24em", height: "27em",
callback: function (resp) { callback: function (resp) {
teaweb.success("保存成功", function () { teaweb.success("保存成功", function () {
window.location.reload() window.location.reload()
@@ -19,7 +19,7 @@ Vue.component("origin-list-box", {
}, },
createBackupOrigin: function () { createBackupOrigin: function () {
teaweb.popup("/servers/server/settings/origins/addPopup?originType=backup&" + this.vParams, { teaweb.popup("/servers/server/settings/origins/addPopup?originType=backup&" + this.vParams, {
height: "24em", height: "27em",
callback: function (resp) { callback: function (resp) {
teaweb.success("保存成功", function () { teaweb.success("保存成功", function () {
window.location.reload() window.location.reload()
@@ -29,7 +29,7 @@ Vue.component("origin-list-box", {
}, },
updateOrigin: function (originId, originType) { updateOrigin: function (originId, originType) {
teaweb.popup("/servers/server/settings/origins/updatePopup?originType=" + originType + "&" + this.vParams + "&originId=" + originId, { teaweb.popup("/servers/server/settings/origins/updatePopup?originType=" + originType + "&" + this.vParams + "&originId=" + originId, {
height: "24em", height: "27em",
callback: function (resp) { callback: function (resp) {
teaweb.success("保存成功", function () { teaweb.success("保存成功", function () {
window.location.reload() window.location.reload()
@@ -85,10 +85,13 @@ Vue.component("origin-list-table", {
</tr> </tr>
</thead> </thead>
<tr v-for="origin in vOrigins"> <tr v-for="origin in vOrigins">
<td :class="{disabled:!origin.isOn}">{{origin.addr}} <td :class="{disabled:!origin.isOn}"><a href="" @click.prevent="updateOrigin(origin.id)">{{origin.addr}} &nbsp;<i class="icon clone outline small"></i></a>
<div v-if="origin.name.length > 0" style="margin-top: 0.5em"> <div v-if="origin.name.length > 0" style="margin-top: 0.5em">
<tiny-basic-label>{{origin.name}}</tiny-basic-label> <tiny-basic-label>{{origin.name}}</tiny-basic-label>
</div> </div>
<div v-if="origin.domains != null && origin.domains.length > 0">
<grey-label v-for="domain in origin.domains">{{domain}}</grey-label>
</div>
</td> </td>
<td :class="{disabled:!origin.isOn}">{{origin.weight}}</td> <td :class="{disabled:!origin.isOn}">{{origin.weight}}</td>
<td> <td>

View File

@@ -1,143 +1,146 @@
Vue.component("reverse-proxy-box", { Vue.component("reverse-proxy-box", {
props: ["v-reverse-proxy-ref", "v-reverse-proxy-config", "v-is-location", "v-family"], props: ["v-reverse-proxy-ref", "v-reverse-proxy-config", "v-is-location", "v-is-group", "v-family"],
data: function () { data: function () {
let reverseProxyRef = this.vReverseProxyRef let reverseProxyRef = this.vReverseProxyRef
if (reverseProxyRef == null) { if (reverseProxyRef == null) {
reverseProxyRef = { reverseProxyRef = {
isPrior: false, isPrior: false,
isOn: false, isOn: false,
reverseProxyId: 0 reverseProxyId: 0
} }
} }
let reverseProxyConfig = this.vReverseProxyConfig let reverseProxyConfig = this.vReverseProxyConfig
if (reverseProxyConfig == null) { if (reverseProxyConfig == null) {
reverseProxyConfig = { reverseProxyConfig = {
requestPath: "", requestPath: "",
stripPrefix: "", stripPrefix: "",
requestURI: "", requestURI: "",
requestHost: "", requestHost: "",
requestHostType: 0, requestHostType: 0,
addHeaders: [], addHeaders: [],
connTimeout: {count: 0, unit: "second"}, connTimeout: {count: 0, unit: "second"},
readTimeout: {count: 0, unit: "second"}, readTimeout: {count: 0, unit: "second"},
idleTimeout: {count: 0, unit: "second"}, idleTimeout: {count: 0, unit: "second"},
maxConns: 0, maxConns: 0,
maxIdleConns: 0 maxIdleConns: 0
} }
} }
if (reverseProxyConfig.addHeaders == null) { if (reverseProxyConfig.addHeaders == null) {
reverseProxyConfig.addHeaders = [] reverseProxyConfig.addHeaders = []
} }
if (reverseProxyConfig.connTimeout == null) { if (reverseProxyConfig.connTimeout == null) {
reverseProxyConfig.connTimeout = {count: 0, unit: "second"} reverseProxyConfig.connTimeout = {count: 0, unit: "second"}
} }
if (reverseProxyConfig.readTimeout == null) { if (reverseProxyConfig.readTimeout == null) {
reverseProxyConfig.readTimeout = {count: 0, unit: "second"} reverseProxyConfig.readTimeout = {count: 0, unit: "second"}
} }
if (reverseProxyConfig.idleTimeout == null) { if (reverseProxyConfig.idleTimeout == null) {
reverseProxyConfig.idleTimeout = {count: 0, unit: "second"} reverseProxyConfig.idleTimeout = {count: 0, unit: "second"}
} }
let forwardHeaders = [ let forwardHeaders = [
{ {
name: "X-Real-IP", name: "X-Real-IP",
isChecked: false isChecked: false
}, },
{ {
name: "X-Forwarded-For", name: "X-Forwarded-For",
isChecked: false isChecked: false
}, },
{ {
name: "X-Forwarded-By", name: "X-Forwarded-By",
isChecked: false isChecked: false
}, },
{ {
name: "X-Forwarded-Host", name: "X-Forwarded-Host",
isChecked: false isChecked: false
}, },
{ {
name: "X-Forwarded-Proto", name: "X-Forwarded-Proto",
isChecked: false isChecked: false
} }
] ]
forwardHeaders.forEach(function (v) { forwardHeaders.forEach(function (v) {
v.isChecked = reverseProxyConfig.addHeaders.$contains(v.name) v.isChecked = reverseProxyConfig.addHeaders.$contains(v.name)
}) })
return { return {
reverseProxyRef: reverseProxyRef, reverseProxyRef: reverseProxyRef,
reverseProxyConfig: reverseProxyConfig, reverseProxyConfig: reverseProxyConfig,
advancedVisible: false, advancedVisible: false,
family: this.vFamily, family: this.vFamily,
forwardHeaders: forwardHeaders forwardHeaders: forwardHeaders
} }
}, },
watch: { watch: {
"reverseProxyConfig.requestHostType": function (v) { "reverseProxyConfig.requestHostType": function (v) {
let requestHostType = parseInt(v) let requestHostType = parseInt(v)
if (isNaN(requestHostType)) { if (isNaN(requestHostType)) {
requestHostType = 0 requestHostType = 0
} }
this.reverseProxyConfig.requestHostType = requestHostType this.reverseProxyConfig.requestHostType = requestHostType
}, },
"reverseProxyConfig.connTimeout.count": function (v) { "reverseProxyConfig.connTimeout.count": function (v) {
let count = parseInt(v) let count = parseInt(v)
if (isNaN(count) || count < 0) { if (isNaN(count) || count < 0) {
count = 0 count = 0
} }
this.reverseProxyConfig.connTimeout.count = count this.reverseProxyConfig.connTimeout.count = count
}, },
"reverseProxyConfig.readTimeout.count": function (v) { "reverseProxyConfig.readTimeout.count": function (v) {
let count = parseInt(v) let count = parseInt(v)
if (isNaN(count) || count < 0) { if (isNaN(count) || count < 0) {
count = 0 count = 0
} }
this.reverseProxyConfig.readTimeout.count = count this.reverseProxyConfig.readTimeout.count = count
}, },
"reverseProxyConfig.idleTimeout.count": function (v) { "reverseProxyConfig.idleTimeout.count": function (v) {
let count = parseInt(v) let count = parseInt(v)
if (isNaN(count) || count < 0) { if (isNaN(count) || count < 0) {
count = 0 count = 0
} }
this.reverseProxyConfig.idleTimeout.count = count this.reverseProxyConfig.idleTimeout.count = count
}, },
"reverseProxyConfig.maxConns": function (v) { "reverseProxyConfig.maxConns": function (v) {
let maxConns = parseInt(v) let maxConns = parseInt(v)
if (isNaN(maxConns) || maxConns < 0) { if (isNaN(maxConns) || maxConns < 0) {
maxConns = 0 maxConns = 0
} }
this.reverseProxyConfig.maxConns = maxConns this.reverseProxyConfig.maxConns = maxConns
}, },
"reverseProxyConfig.maxIdleConns": function (v) { "reverseProxyConfig.maxIdleConns": function (v) {
let maxIdleConns = parseInt(v) let maxIdleConns = parseInt(v)
if (isNaN(maxIdleConns) || maxIdleConns < 0) { if (isNaN(maxIdleConns) || maxIdleConns < 0) {
maxIdleConns = 0 maxIdleConns = 0
} }
this.reverseProxyConfig.maxIdleConns = maxIdleConns this.reverseProxyConfig.maxIdleConns = maxIdleConns
}, },
}, },
methods: { methods: {
isOn: function () { isOn: function () {
return (!this.vIsLocation || this.reverseProxyRef.isPrior) && this.reverseProxyRef.isOn if (this.vIsLocation || this.vIsGroup) {
}, return this.reverseProxyRef.isPrior && this.reverseProxyRef.isOn
changeAdvancedVisible: function (v) { }
this.advancedVisible = v return this.reverseProxyRef.isOn
}, },
changeAddHeader: function () { changeAdvancedVisible: function (v) {
this.reverseProxyConfig.addHeaders = this.forwardHeaders.filter(function (v) { this.advancedVisible = v
return v.isChecked },
}).map(function (v) { changeAddHeader: function () {
return v.name this.reverseProxyConfig.addHeaders = this.forwardHeaders.filter(function (v) {
}) return v.isChecked
} }).map(function (v) {
}, return v.name
template: `<div> })
}
},
template: `<div>
<input type="hidden" name="reverseProxyRefJSON" :value="JSON.stringify(reverseProxyRef)"/> <input type="hidden" name="reverseProxyRefJSON" :value="JSON.stringify(reverseProxyRef)"/>
<input type="hidden" name="reverseProxyJSON" :value="JSON.stringify(reverseProxyConfig)"/> <input type="hidden" name="reverseProxyJSON" :value="JSON.stringify(reverseProxyConfig)"/>
<table class="ui table selectable definition"> <table class="ui table selectable definition">
<prior-checkbox :v-config="reverseProxyRef" v-if="vIsLocation"></prior-checkbox> <prior-checkbox :v-config="reverseProxyRef" v-if="vIsLocation || vIsGroup"></prior-checkbox>
<tbody v-show="!vIsLocation || reverseProxyRef.isPrior"> <tbody v-show="(!vIsLocation && !vIsGroup) || reverseProxyRef.isPrior">
<tr> <tr>
<td class="title">是否启用反向代理</td> <td class="title">是否启用反向代理</td>
<td> <td>

View File

@@ -15,7 +15,7 @@ Vue.component("server-group-selector", {
let groupIds = this.groups.map(function (v) { let groupIds = this.groups.map(function (v) {
return v.id.toString() return v.id.toString()
}).join(",") }).join(",")
teaweb.popup("/servers/components/groups/selectPopup?selectedGroupIds=" + groupIds, { teaweb.popup("/servers/groups/selectPopup?selectedGroupIds=" + groupIds, {
callback: function (resp) { callback: function (resp) {
that.groups.push(resp.data.group) that.groups.push(resp.data.group)
} }
@@ -23,7 +23,7 @@ Vue.component("server-group-selector", {
}, },
addGroup: function () { addGroup: function () {
let that = this let that = this
teaweb.popup("/servers/components/groups/createPopup", { teaweb.popup("/servers/groups/createPopup", {
callback: function (resp) { callback: function (resp) {
that.groups.push(resp.data.group) that.groups.push(resp.data.group)
} }

View File

@@ -73,9 +73,10 @@ window.teaweb = {
// 加载 // 加载
if (typeof Pikaday == "undefined") { if (typeof Pikaday == "undefined") {
let that = this let that = this
this.loadJS("/js/moment.min.js") this.loadJS("/js/moment.min.js", function () {
this.loadJS("/js/pikaday.js", function () { that.loadJS("/js/pikaday.js", function () {
that.datepicker(element, callback) that.datepicker(element, callback)
})
}) })
this.loadCSS("/js/pikaday.css") this.loadCSS("/js/pikaday.css")
this.loadCSS("/js/pikaday.theme.css") this.loadCSS("/js/pikaday.theme.css")

View File

@@ -57,6 +57,12 @@
.left-box.without-tabbar { .left-box.without-tabbar {
top: 3em; top: 3em;
} }
.left-box.with-menu {
top: 10em;
}
.left-box.without-menu {
top: 6em;
}
.right-box { .right-box {
position: fixed; position: fixed;
top: 7.5em; top: 7.5em;
@@ -80,6 +86,12 @@ body.expanded .right-box {
.right-box.without-tabbar { .right-box.without-tabbar {
top: 3em; top: 3em;
} }
.right-box.with-menu {
top: 10em;
}
.right-box.without-menu {
top: 6em;
}
.main.without-footer .left-box { .main.without-footer .left-box {
bottom: 0.2em; bottom: 0.2em;
} }
@@ -174,6 +186,9 @@ div.margin,
p.margin { p.margin {
margin-top: 1em; margin-top: 1em;
} }
.opacity-mask {
opacity: 0.6;
}
/** 操作按钮容器 **/ /** 操作按钮容器 **/
.op.one { .op.one {
width: 4em; width: 4em;

File diff suppressed because one or more lines are too long

View File

@@ -63,7 +63,7 @@
<a href="" class="item" title="点击切换界面风格" @click.prevent="changeTheme()"><i class="icon adjust"></i></a> <a href="" class="item" title="点击切换界面风格" @click.prevent="changeTheme()"><i class="icon adjust"></i></a>
<!-- 企业版 --> <!-- 企业版 -->
<!-- <a :href="'/settings/authority'" class="item" title="业版" :v-if="teaIsPlus"><i class="icon gem outline yellow"></i></a>--> <!-- <a :href="'/settings/authority'" class="item" title="业版" :v-if="teaIsPlus"><i class="icon gem outline yellow"></i></a>-->
<!-- 退出登录 --> <!-- 退出登录 -->
<a :href="Tea.url('logout')" class="item" title="安全退出登录"><i class="icon sign out"></i> <a :href="Tea.url('logout')" class="item" title="安全退出登录"><i class="icon sign out"></i>

View File

@@ -103,6 +103,10 @@ div.margin, p.margin {
margin-top: 1em; margin-top: 1em;
} }
.opacity-mask {
opacity: 0.6;
}
/** 操作按钮容器 **/ /** 操作按钮容器 **/
.op.one { .op.one {
width: 4em; width: 4em;
@@ -799,4 +803,4 @@ td {
// input // input
input.error { input.error {
border: 1px #e0b4b4 solid !important; border: 1px #e0b4b4 solid !important;
} }

View File

@@ -79,6 +79,14 @@
top: 3em; top: 3em;
} }
.left-box.with-menu {
top: 10em;
}
.left-box.without-menu {
top: 6em;
}
.right-box { .right-box {
position: fixed; position: fixed;
top: 7.5em; top: 7.5em;
@@ -107,6 +115,13 @@ body.expanded .right-box {
top: 3em; top: 3em;
} }
.right-box.with-menu {
top: 10em;
}
.right-box.without-menu {
top: 6em;
}
// main // main
.main.without-footer .left-box { .main.without-footer .left-box {

View File

@@ -0,0 +1,9 @@
<div class="margin"></div>
<div class="left-box with-menu" :class="{disabled:leftMenuItemIsDisabled}">
<div class="ui menu text blue vertical small">
<a class="item" v-for="item in leftMenuItems" :href="item.url" :class="{active:item.isActive, separator:item.name == '-', on:item.isOn, off:item.isOff}">
<span v-if="item.name != '-'"><i class="icon play tiny" :style="{'visibility':item.isActive ? 'visible' : 'hidden'}"></i>{{item.name}}<var v-if="item.isOff"></var></span>
</a>
</div>
</div>

View File

@@ -0,0 +1,9 @@
<div class="margin"></div>
<div class="left-box without-menu" :class="{disabled:leftMenuItemIsDisabled}">
<div class="ui menu text blue vertical small">
<a class="item" v-for="item in leftMenuItems" :href="item.url" :class="{active:item.isActive, separator:item.name == '-', on:item.isOn, off:item.isOff}">
<span v-if="item.name != '-'"><i class="icon play tiny" :style="{'visibility':item.isActive ? 'visible' : 'hidden'}"></i>{{item.name}}<var v-if="item.isOff"></var></span>
</a>
</div>
</div>

View File

@@ -22,7 +22,7 @@
<td style="text-align: center;"><i class="icon bars handle grey"></i> </td> <td style="text-align: center;"><i class="icon bars handle grey"></i> </td>
<td>{{group.name}}</td> <td>{{group.name}}</td>
<td class="center"> <td class="center">
<span v-if="group.countNodes > 0">{{group.countNodes}}</span> <a :href="'/clusters/cluster/nodes?clusterId=' + clusterId + '&groupId=' + group.id" v-if="group.countNodes > 0">{{group.countNodes}}</a>
<span v-else class="disabled">0</span> <span v-else class="disabled">0</span>
</td> </td>
<td> <td>

View File

@@ -12,7 +12,7 @@
</td> </td>
<td> <td>
<source-code-box id="cluster-config-box" type="text/yaml">rpc: <source-code-box id="cluster-config-box" type="text/yaml">rpc:
endpoints: [ {{cluster.endpoints}} ] endpoints: [ {{cluster.endpoints}} ]
clusterId: "{{cluster.uniqueId}}" clusterId: "{{cluster.uniqueId}}"
secret: "{{cluster.secret}}"</source-code-box> secret: "{{cluster.secret}}"</source-code-box>
</td> </td>

View File

@@ -1,11 +1,10 @@
<second-menu> <second-menu>
<menu-item :href="'/clusters/cluster/nodes?clusterId=' + clusterId">节点列表</menu-item> <a :href="'/clusters/cluster/nodes?clusterId=' + clusterId" class="item" style="padding-right: 0">{{currentClusterName}} &raquo;</a>
<span class="item disabled">|</span> <a :href="'/clusters/cluster/nodes?clusterId=' + clusterId + '&groupId=' + node.group.id" v-if="node.group != null" class="item" style="padding-left: 0"> &nbsp; {{node.group.name}} &raquo;</a>
<menu-item :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id" code="node" <menu-item :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id" code="node"
v-if="!teaIsPlus">"{{node.name}}"节点详情</menu-item> v-if="!teaIsPlus" style="padding-left: 0">"{{node.name}}"节点详情</menu-item>
<menu-item :href="'/clusters/cluster/node/boards?clusterId=' + clusterId + '&nodeId=' + node.id" code="board" v-if="teaIsPlus">"{{node.name}}" 节点看板</menu-item> <menu-item :href="'/clusters/cluster/node/boards?clusterId=' + clusterId + '&nodeId=' + node.id" code="board" v-if="teaIsPlus" style="padding-left: 0">"{{node.name}}" 节点看板</menu-item>
<menu-item :href="'/clusters/cluster/node/detail?clusterId=' + clusterId + '&nodeId=' + node.id" code="node" v-if="teaIsPlus">节点详情</menu-item> <menu-item :href="'/clusters/cluster/node/detail?clusterId=' + clusterId + '&nodeId=' + node.id" code="node" v-if="teaIsPlus" style="padding-left: 0">节点详情</menu-item>
<menu-item :href="'/clusters/cluster/node/thresholds?clusterId=' + clusterId + '&nodeId=' + node.id" code="threshold" v-if="teaIsPlus">阈值设置</menu-item>
<menu-item :href="'/clusters/cluster/node/logs?clusterId=' + clusterId + '&nodeId=' + node.id" code="log">运行日志</menu-item> <menu-item :href="'/clusters/cluster/node/logs?clusterId=' + clusterId + '&nodeId=' + node.id" code="log">运行日志</menu-item>
<menu-item :href="'/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" code="install">安装节点</menu-item> <menu-item :href="'/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" code="install">安装节点</menu-item>
<menu-item :href="'/clusters/cluster/node/update?clusterId=' + clusterId + '&nodeId=' + node.id" code="update">修改设置</menu-item> <menu-item :href="'/clusters/cluster/node/update?clusterId=' + clusterId + '&nodeId=' + node.id" code="update">修改设置</menu-item>

Some files were not shown because too many files have changed in this diff Show More