Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f738ba9152 | ||
|
|
95c27119ac | ||
|
|
2b2b516788 | ||
|
|
0bb63b5bb7 | ||
|
|
48012072d7 | ||
|
|
0053949bc0 | ||
|
|
88e7246366 | ||
|
|
fbedf3b605 | ||
|
|
d5659e627d | ||
|
|
709d4dc805 | ||
|
|
37f052e9a5 | ||
|
|
58c765e97f | ||
|
|
da332c2756 | ||
|
|
e9d329bf8b | ||
|
|
775b46cf8f | ||
|
|
c99eb54811 | ||
|
|
7917c68b6f | ||
|
|
75ce1490cc | ||
|
|
6f1cd668b6 | ||
|
|
5b7cb59997 | ||
|
|
67242ec80e | ||
|
|
2af5e059eb | ||
|
|
1d992b0e97 | ||
|
|
0c650987d6 | ||
|
|
e8af3960f8 | ||
|
|
1d95087abb | ||
|
|
c350fceef3 | ||
|
|
e6970abcb8 | ||
|
|
9cf5f56e59 | ||
|
|
c2ebf81e6c | ||
|
|
19a2af8bfa | ||
|
|
df5c1262d2 | ||
|
|
26340110c1 | ||
|
|
452f03bb78 | ||
|
|
609794b2d8 | ||
|
|
554d0daf6d | ||
|
|
e4015282a5 | ||
|
|
a7453a4baa | ||
|
|
913a98b4de | ||
|
|
89f391ca22 | ||
|
|
e585149a7e |
@@ -6,3 +6,4 @@
|
||||
./build.sh linux mips64
|
||||
./build.sh linux mips64le
|
||||
./build.sh darwin amd64
|
||||
./build.sh darwin arm64
|
||||
|
||||
1
build/licenses/README.md
Normal file
1
build/licenses/README.md
Normal file
@@ -0,0 +1 @@
|
||||
这个目录下我们列举了所有需要公开声明的第三方License,如果有遗漏,烦请告知 iwind.liu@gmail.com。再次感谢这些开源软件项目和贡献人员!
|
||||
30
build/licenses/miekg-dns.md
Normal file
30
build/licenses/miekg-dns.md
Normal file
@@ -0,0 +1,30 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
As this is fork of the official Go code the same license applies.
|
||||
Extensions of the original work are copyright (c) 2011 Miek Gieben
|
||||
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/apps"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web"
|
||||
@@ -13,7 +14,14 @@ func main() {
|
||||
app := apps.NewAppCmd().
|
||||
Version(teaconst.Version).
|
||||
Product(teaconst.ProductName).
|
||||
Usage(teaconst.ProcessName + " [-v|start|stop|restart|service|daemon]")
|
||||
Usage(teaconst.ProcessName+" [-v|start|stop|restart|service|daemon|reset]").
|
||||
Option("-h", "show this help").
|
||||
Option("-v", "show version").
|
||||
Option("start", "start the service").
|
||||
Option("stop", "stop the service").
|
||||
Option("service", "register service into systemd").
|
||||
Option("daemon", "start the service with daemon").
|
||||
Option("reset", "reset configs")
|
||||
|
||||
app.On("daemon", func() {
|
||||
nodes.NewAdminNode().Daemon()
|
||||
@@ -26,6 +34,14 @@ func main() {
|
||||
}
|
||||
fmt.Println("done")
|
||||
})
|
||||
app.On("reset", func() {
|
||||
err := configs.ResetAPIConfig()
|
||||
if err != nil {
|
||||
fmt.Println("[ERROR]reset failed: " + err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Println("done")
|
||||
})
|
||||
app.Run(func() {
|
||||
adminNode := nodes.NewAdminNode()
|
||||
adminNode.Run()
|
||||
|
||||
@@ -59,6 +59,49 @@ func LoadAPIConfig() (*APIConfig, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// ResetAPIConfig 重置配置
|
||||
func ResetAPIConfig() error {
|
||||
filename := "api.yaml"
|
||||
|
||||
{
|
||||
configFile := Tea.ConfigFile(filename)
|
||||
stat, err := os.Stat(configFile)
|
||||
if err == nil && !stat.IsDir() {
|
||||
err = os.Remove(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重置 ~/.edge-admin/api.yaml
|
||||
homeDir, homeErr := os.UserHomeDir()
|
||||
if homeErr == nil {
|
||||
configFile := homeDir + "/." + teaconst.ProcessName + "/" + filename
|
||||
stat, err := os.Stat(configFile)
|
||||
if err == nil && !stat.IsDir() {
|
||||
err = os.Remove(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重置 /etc/edge-admin/api.yaml
|
||||
{
|
||||
configFile := "/etc/" + teaconst.ProcessName + "/" + filename
|
||||
stat, err := os.Stat(configFile)
|
||||
if err == nil && !stat.IsDir() {
|
||||
err = os.Remove(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteFile 写入API配置
|
||||
func (this *APIConfig) WriteFile(path string) error {
|
||||
data, err := yaml.Marshal(this)
|
||||
@@ -84,7 +127,7 @@ func (this *APIConfig) WriteFile(path string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// 写入 /etc/.edge-admin
|
||||
// 写入 /etc/edge-admin
|
||||
{
|
||||
dir := "/etc/" + teaconst.ProcessName
|
||||
stat, err := os.Stat(dir)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.0.13"
|
||||
Version = "0.1.1"
|
||||
|
||||
ProductName = "Edge Admin"
|
||||
ProcessName = "edge-admin"
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RPC客户端
|
||||
// RPCClient RPC客户端
|
||||
type RPCClient struct {
|
||||
apiConfig *configs.APIConfig
|
||||
conns []*grpc.ClientConn
|
||||
@@ -30,7 +30,7 @@ type RPCClient struct {
|
||||
locker sync.Mutex
|
||||
}
|
||||
|
||||
// 构造新的RPC客户端
|
||||
// NewRPCClient 构造新的RPC客户端
|
||||
func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
|
||||
if apiConfig == nil {
|
||||
return nil, errors.New("api config should not be nil")
|
||||
@@ -91,6 +91,14 @@ func (this *RPCClient) NodeIPAddressRPC() pb.NodeIPAddressServiceClient {
|
||||
return pb.NewNodeIPAddressServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) NodeValueRPC() pb.NodeValueServiceClient {
|
||||
return pb.NewNodeValueServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) NodeThresholdRPC() pb.NodeThresholdServiceClient {
|
||||
return pb.NewNodeThresholdServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) ServerRPC() pb.ServerServiceClient {
|
||||
return pb.NewServerServiceClient(this.pickConn())
|
||||
}
|
||||
@@ -212,6 +220,10 @@ func (this *RPCClient) HTTPAccessLogRPC() pb.HTTPAccessLogServiceClient {
|
||||
return pb.NewHTTPAccessLogServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) HTTPFastcgiRPC() pb.HTTPFastcgiServiceClient {
|
||||
return pb.NewHTTPFastcgiServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) SSLCertRPC() pb.SSLCertServiceClient {
|
||||
return pb.NewSSLCertServiceClient(this.pickConn())
|
||||
}
|
||||
@@ -336,6 +348,10 @@ func (this *RPCClient) AuthorityNodeRPC() pb.AuthorityNodeServiceClient {
|
||||
return pb.NewAuthorityNodeServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) LatestItemRPC() pb.LatestItemServiceClient {
|
||||
return pb.NewLatestItemServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
// Context 构造Admin上下文
|
||||
func (this *RPCClient) Context(adminId int64) context.Context {
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -37,7 +37,7 @@ func TestRPC_Dial_HTTP(t *testing.T) {
|
||||
RPC: struct {
|
||||
Endpoints []string `yaml:"endpoints"`
|
||||
}{
|
||||
Endpoints: []string{"127.0.0.1:8003"},
|
||||
Endpoints: []string{"http://127.0.0.1:8004"},
|
||||
},
|
||||
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||
@@ -58,7 +58,7 @@ func TestRPC_Dial_HTTP_2(t *testing.T) {
|
||||
RPC: struct {
|
||||
Endpoints []string `yaml:"endpoints"`
|
||||
}{
|
||||
Endpoints: []string{"http://127.0.0.1:8003"},
|
||||
Endpoints: []string{"https://127.0.0.1:8003"},
|
||||
},
|
||||
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||
|
||||
@@ -30,7 +30,7 @@ func (this *Piece) IncreaseInt64(key uint64, delta int64, expiredAt int64) (resu
|
||||
this.locker.Lock()
|
||||
item, ok := this.m[key]
|
||||
if ok {
|
||||
result := types.Int64(item.Value) + delta
|
||||
result = types.Int64(item.Value) + delta
|
||||
item.Value = result
|
||||
item.expiredAt = expiredAt
|
||||
} else {
|
||||
|
||||
@@ -22,8 +22,12 @@ func FormatBytes(bytes int64) string {
|
||||
return fmt.Sprintf("%.2fMB", float64(bytes)/1024/1024)
|
||||
} else if bytes < 1024*1024*1024*1024 {
|
||||
return fmt.Sprintf("%.2fGB", float64(bytes)/1024/1024/1024)
|
||||
} else if bytes < 1024*1024*1024*1024*1024 {
|
||||
return fmt.Sprintf("%.2fTB", float64(bytes)/1024/1024/1024/1024)
|
||||
} else if bytes < 1024*1024*1024*1024*1024*1024 {
|
||||
return fmt.Sprintf("%.2fPB", float64(bytes)/1024/1024/1024/1024/1024)
|
||||
} else {
|
||||
return fmt.Sprintf("%.2fPB", float64(bytes)/1024/1024/1024/1024)
|
||||
return fmt.Sprintf("%.2fEB", float64(bytes)/1024/1024/1024/1024/1024/1024)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +40,11 @@ func FormatBits(bits int64) string {
|
||||
return fmt.Sprintf("%.2fMB", float64(bits)/1000/1000)
|
||||
} else if bits < 1000*1000*1000*1000 {
|
||||
return fmt.Sprintf("%.2fGB", float64(bits)/1000/1000/1000)
|
||||
} else if bits < 1000*1000*1000*1000*1000 {
|
||||
return fmt.Sprintf("%.2fTB", float64(bits)/1000/1000/1000/1000)
|
||||
} else if bits < 1000*1000*1000*1000*1000*1000 {
|
||||
return fmt.Sprintf("%.2fPB", float64(bits)/1000/1000/1000/1000/1000)
|
||||
} else {
|
||||
return fmt.Sprintf("%.2fPB", float64(bits)/1000/1000/1000/1000)
|
||||
return fmt.Sprintf("%.2fEB", float64(bits)/1000/1000/1000/1000/1000/1000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,5 +203,15 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["regions"] = regionMaps
|
||||
|
||||
// 记录最近访问
|
||||
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
||||
ItemType: "cluster",
|
||||
ItemId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/groups"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/monitor"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/thresholds"
|
||||
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
@@ -37,6 +39,14 @@ func init() {
|
||||
Post("/node/start", new(node.StartAction)).
|
||||
Post("/node/stop", new(node.StopAction)).
|
||||
Post("/node/up", new(node.UpAction)).
|
||||
Get("/node/monitor", new(monitor.IndexAction)).
|
||||
Post("/node/monitor/cpu", new(monitor.CpuAction)).
|
||||
Post("/node/monitor/memory", new(monitor.MemoryAction)).
|
||||
Post("/node/monitor/load", new(monitor.LoadAction)).
|
||||
Post("/node/monitor/trafficIn", new(monitor.TrafficInAction)).
|
||||
Post("/node/monitor/trafficOut", new(monitor.TrafficOutAction)).
|
||||
Post("/node/monitor/connections", new(monitor.ConnectionsAction)).
|
||||
Get("/node/thresholds", new(thresholds.IndexAction)).
|
||||
|
||||
// 分组相关
|
||||
Get("/groups", new(groups.IndexAction)).
|
||||
|
||||
@@ -17,13 +17,25 @@ func (this *LogsAction) Init() {
|
||||
}
|
||||
|
||||
func (this *LogsAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
NodeId int64
|
||||
DayFrom string
|
||||
DayTo string
|
||||
Keyword string
|
||||
Level string
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["dayFrom"] = params.DayFrom
|
||||
this.Data["dayTo"] = params.DayTo
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["level"] = params.Level
|
||||
|
||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||
Role: "node",
|
||||
NodeId: params.NodeId,
|
||||
Role: "node",
|
||||
NodeId: params.NodeId,
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -33,10 +45,14 @@ func (this *LogsAction) RunGet(params struct {
|
||||
page := this.NewPage(count, 20)
|
||||
|
||||
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
|
||||
NodeId: params.NodeId,
|
||||
Role: "node",
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
NodeId: params.NodeId,
|
||||
Role: "node",
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
|
||||
logs := []maps.Map{}
|
||||
@@ -47,6 +63,7 @@ func (this *LogsAction) RunGet(params struct {
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
|
||||
"level": log.Level,
|
||||
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
|
||||
"count": log.Count,
|
||||
})
|
||||
}
|
||||
this.Data["logs"] = logs
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ConnectionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ConnectionsAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
||||
Role: "node",
|
||||
NodeId: params.NodeId,
|
||||
Item: nodeconfigs.NodeValueItemConnections,
|
||||
Range: nodeconfigs.NodeValueRangeMinute,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
valuesMap := map[string]int64{} // YmdHi => count
|
||||
for _, v := range resp.NodeValues {
|
||||
if len(v.ValueJSON) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
valueMap := maps.Map{}
|
||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetInt64("total")
|
||||
}
|
||||
|
||||
// 过去一个小时
|
||||
result := []maps.Map{}
|
||||
for i := 60; i >= 1; i-- {
|
||||
timestamp := time.Now().Unix() - int64(i)*60
|
||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
||||
total, ok := valuesMap[minute]
|
||||
if ok {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": total,
|
||||
"text": numberutils.FormatInt64(total),
|
||||
})
|
||||
} else {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": 0,
|
||||
"text": "0",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["values"] = result
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CpuAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CpuAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
||||
Role: "node",
|
||||
NodeId: params.NodeId,
|
||||
Item: nodeconfigs.NodeValueItemCPU,
|
||||
Range: nodeconfigs.NodeValueRangeMinute,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
valuesMap := map[string]float32{} // YmdHi => usage
|
||||
for _, v := range resp.NodeValues {
|
||||
if len(v.ValueJSON) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
valueMap := maps.Map{}
|
||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetFloat32("usage") * 100
|
||||
}
|
||||
|
||||
// 过去一个小时
|
||||
result := []maps.Map{}
|
||||
for i := 60; i >= 1; i-- {
|
||||
timestamp := time.Now().Unix() - int64(i)*60
|
||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
||||
total, ok := valuesMap[minute]
|
||||
if ok {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": total,
|
||||
"text": fmt.Sprintf("%.2f%%", total),
|
||||
})
|
||||
} else {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": 0,
|
||||
"text": "0.0%",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["values"] = result
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package monitor
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "monitor")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LoadAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *LoadAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
||||
Role: "node",
|
||||
NodeId: params.NodeId,
|
||||
Item: nodeconfigs.NodeValueItemLoad,
|
||||
Range: nodeconfigs.NodeValueRangeMinute,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
valuesMap := map[string]float32{} // YmdHi => load5m
|
||||
for _, v := range resp.NodeValues {
|
||||
if len(v.ValueJSON) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
valueMap := maps.Map{}
|
||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetFloat32("load5m")
|
||||
}
|
||||
|
||||
// 过去一个小时
|
||||
result := []maps.Map{}
|
||||
for i := 60; i >= 1; i-- {
|
||||
timestamp := time.Now().Unix() - int64(i)*60
|
||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
||||
total, ok := valuesMap[minute]
|
||||
if ok {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": total,
|
||||
"text": fmt.Sprintf("5分钟: %.2f", total),
|
||||
})
|
||||
} else {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": 0,
|
||||
"text": "5分钟: 0.0",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["values"] = result
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MemoryAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *MemoryAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
||||
Role: "node",
|
||||
NodeId: params.NodeId,
|
||||
Item: nodeconfigs.NodeValueItemMemory,
|
||||
Range: nodeconfigs.NodeValueRangeMinute,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
valuesMap := map[string]float32{} // YmdHi => usage
|
||||
for _, v := range resp.NodeValues {
|
||||
if len(v.ValueJSON) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
valueMap := maps.Map{}
|
||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetFloat32("usage") * 100
|
||||
}
|
||||
|
||||
// 过去一个小时
|
||||
result := []maps.Map{}
|
||||
for i := 60; i >= 1; i-- {
|
||||
timestamp := time.Now().Unix() - int64(i)*60
|
||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
||||
total, ok := valuesMap[minute]
|
||||
if ok {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": total,
|
||||
"text": fmt.Sprintf("%.2f%%", total),
|
||||
})
|
||||
} else {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": 0,
|
||||
"text": "0.0%",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["values"] = result
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TrafficInAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TrafficInAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
||||
Role: "node",
|
||||
NodeId: params.NodeId,
|
||||
Item: nodeconfigs.NodeValueItemTrafficIn,
|
||||
Range: nodeconfigs.NodeValueRangeMinute,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
valuesMap := map[string]int64{} // YmdHi => bytes
|
||||
for _, v := range resp.NodeValues {
|
||||
if len(v.ValueJSON) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
valueMap := maps.Map{}
|
||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetInt64("total")
|
||||
}
|
||||
|
||||
// 过去一个小时
|
||||
result := []maps.Map{}
|
||||
for i := 60; i >= 1; i-- {
|
||||
timestamp := time.Now().Unix() - int64(i)*60
|
||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
||||
total, ok := valuesMap[minute]
|
||||
if ok {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": total / 60,
|
||||
"text": numberutils.FormatBytes(total / 60),
|
||||
})
|
||||
} else {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": 0,
|
||||
"text": numberutils.FormatBytes(0),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["values"] = result
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TrafficOutAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TrafficOutAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
||||
Role: "node",
|
||||
NodeId: params.NodeId,
|
||||
Item: nodeconfigs.NodeValueItemTrafficOut,
|
||||
Range: nodeconfigs.NodeValueRangeMinute,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
valuesMap := map[string]int64{} // YmdHi => bytes
|
||||
for _, v := range resp.NodeValues {
|
||||
if len(v.ValueJSON) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
valueMap := maps.Map{}
|
||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetInt64("total")
|
||||
}
|
||||
|
||||
// 过去一个小时
|
||||
result := []maps.Map{}
|
||||
for i := 60; i >= 1; i-- {
|
||||
timestamp := time.Now().Unix() - int64(i)*60
|
||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
||||
total, ok := valuesMap[minute]
|
||||
if ok {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": total / 60,
|
||||
"text": numberutils.FormatBytes(total / 60),
|
||||
})
|
||||
} else {
|
||||
result = append(result, maps.Map{
|
||||
"label": timeutil.FormatTime("H:i", timestamp),
|
||||
"value": 0,
|
||||
"text": numberutils.FormatBytes(0),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["values"] = result
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package node
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
@@ -114,17 +115,17 @@ func (this *NodeAction) RunGet(params struct {
|
||||
grantMap := maps.Map{}
|
||||
grantId := loginParams.GetInt64("grantId")
|
||||
if grantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledGrant(this.AdminContext(), &pb.FindEnabledGrantRequest{GrantId: grantId})
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.Grant != nil {
|
||||
if grantResp.NodeGrant != nil {
|
||||
grantMap = maps.Map{
|
||||
"id": grantResp.Grant.Id,
|
||||
"name": grantResp.Grant.Name,
|
||||
"method": grantResp.Grant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.Grant.Method),
|
||||
"id": grantResp.NodeGrant.Id,
|
||||
"name": grantResp.NodeGrant.Name,
|
||||
"method": grantResp.NodeGrant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,6 +186,33 @@ func (this *NodeAction) 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",
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
@@ -199,24 +227,29 @@ func (this *NodeAction) RunGet(params struct {
|
||||
"isOn": node.IsOn,
|
||||
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||
"connectionCount": status.ConnectionCount,
|
||||
"buildVersion": status.BuildVersion,
|
||||
"cpuPhysicalCount": status.CPUPhysicalCount,
|
||||
"cpuLogicalCount": status.CPULogicalCount,
|
||||
"load1m": fmt.Sprintf("%.2f", status.Load1m),
|
||||
"load5m": fmt.Sprintf("%.2f", status.Load5m),
|
||||
"load15m": fmt.Sprintf("%.2f", status.Load15m),
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||
"connectionCount": status.ConnectionCount,
|
||||
"buildVersion": status.BuildVersion,
|
||||
"cpuPhysicalCount": status.CPUPhysicalCount,
|
||||
"cpuLogicalCount": status.CPULogicalCount,
|
||||
"load1m": fmt.Sprintf("%.2f", status.Load1m),
|
||||
"load5m": fmt.Sprintf("%.2f", status.Load5m),
|
||||
"load15m": fmt.Sprintf("%.2f", status.Load15m),
|
||||
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
|
||||
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
|
||||
},
|
||||
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
|
||||
"maxCacheDiskCapacity": maxCacheDiskCapacity,
|
||||
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package thresholds
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "threshold")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
// 列出所有阈值
|
||||
thresholdsResp, err := this.RPC().NodeThresholdRPC().FindAllEnabledNodeThresholds(this.AdminContext(), &pb.FindAllEnabledNodeThresholdsRequest{
|
||||
Role: "node",
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
thresholdMaps := []maps.Map{}
|
||||
for _, threshold := range thresholdsResp.NodeThresholds {
|
||||
thresholdMaps = append(thresholdMaps, maps.Map{
|
||||
"id": threshold.Id,
|
||||
"itemName": nodeconfigs.FindNodeValueItemName(threshold.Item),
|
||||
"paramName": nodeconfigs.FindNodeValueItemParamName(threshold.Item, threshold.Param),
|
||||
"operatorName": nodeconfigs.FindNodeValueOperatorName(threshold.Operator),
|
||||
"value": nodeconfigs.UnmarshalNodeValue(threshold.ValueJSON),
|
||||
"sumMethodName": nodeconfigs.FindNodeValueSumMethodName(threshold.SumMethod),
|
||||
"duration": threshold.Duration,
|
||||
"durationUnitName": nodeconfigs.FindNodeValueDurationUnitName(threshold.DurationUnit),
|
||||
"isOn": threshold.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["thresholds"] = thresholdMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"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/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
@@ -114,17 +115,17 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
grantMap := maps.Map{}
|
||||
grantId := loginParams.GetInt64("grantId")
|
||||
if grantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledGrant(this.AdminContext(), &pb.FindEnabledGrantRequest{GrantId: grantId})
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.Grant != nil {
|
||||
if grantResp.NodeGrant != nil {
|
||||
grantMap = maps.Map{
|
||||
"id": grantResp.Grant.Id,
|
||||
"name": grantResp.Grant.Name,
|
||||
"method": grantResp.Grant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.Grant.Method),
|
||||
"id": grantResp.NodeGrant.Id,
|
||||
"name": grantResp.NodeGrant.Name,
|
||||
"method": grantResp.NodeGrant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,16 +157,45 @@ 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",
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddresses": ipAddressMaps,
|
||||
"cluster": clusterMap,
|
||||
"login": loginMap,
|
||||
"maxCPU": node.MaxCPU,
|
||||
"isOn": node.IsOn,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddresses": ipAddressMaps,
|
||||
"cluster": clusterMap,
|
||||
"login": loginMap,
|
||||
"maxCPU": node.MaxCPU,
|
||||
"isOn": node.IsOn,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"maxCacheDiskCapacity": maxCacheDiskCapacity,
|
||||
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
|
||||
}
|
||||
|
||||
// 所有集群
|
||||
@@ -190,18 +220,20 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
LoginId int64
|
||||
NodeId int64
|
||||
GroupId int64
|
||||
RegionId int64
|
||||
Name string
|
||||
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
||||
ClusterId int64
|
||||
GrantId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
MaxCPU int32
|
||||
IsOn bool
|
||||
LoginId int64
|
||||
NodeId int64
|
||||
GroupId int64
|
||||
RegionId int64
|
||||
Name string
|
||||
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
||||
ClusterId int64
|
||||
GrantId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
MaxCPU int32
|
||||
IsOn bool
|
||||
MaxCacheDiskCapacityJSON []byte
|
||||
MaxCacheMemoryCapacityJSON []byte
|
||||
|
||||
DnsDomainId int64
|
||||
DnsRoutesJSON []byte
|
||||
@@ -258,18 +290,49 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
}.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{
|
||||
NodeId: params.NodeId,
|
||||
GroupId: params.GroupId,
|
||||
RegionId: params.RegionId,
|
||||
Name: params.Name,
|
||||
NodeClusterId: params.ClusterId,
|
||||
Login: loginInfo,
|
||||
MaxCPU: params.MaxCPU,
|
||||
IsOn: params.IsOn,
|
||||
DnsDomainId: params.DnsDomainId,
|
||||
DnsRoutes: dnsRouteCodes,
|
||||
NodeId: params.NodeId,
|
||||
GroupId: params.GroupId,
|
||||
RegionId: params.RegionId,
|
||||
Name: params.Name,
|
||||
NodeClusterId: params.ClusterId,
|
||||
Login: loginInfo,
|
||||
MaxCPU: params.MaxCPU,
|
||||
IsOn: params.IsOn,
|
||||
DnsDomainId: params.DnsDomainId,
|
||||
DnsRoutes: dnsRouteCodes,
|
||||
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
||||
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -36,12 +36,12 @@ func (this *IndexAction) RunGet(params struct {
|
||||
var grantMap interface{} = nil
|
||||
|
||||
if cluster.GrantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledGrant(this.AdminContext(), &pb.FindEnabledGrantRequest{GrantId: cluster.GrantId})
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: cluster.GrantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
grant := grantResp.Grant
|
||||
grant := grantResp.NodeGrant
|
||||
if grant != nil {
|
||||
grantMap = maps.Map{
|
||||
"id": grant.Id,
|
||||
@@ -62,7 +62,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
// 保存设置
|
||||
// RunPost 保存设置
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Name string
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/health"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/message"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/services"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/thresholds"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/toa"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/waf"
|
||||
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||
@@ -59,6 +60,13 @@ func init() {
|
||||
GetPost("/updatePopup", new(firewallActions.UpdatePopupAction)).
|
||||
Post("/delete", new(firewallActions.DeleteAction)).
|
||||
|
||||
// 阈值
|
||||
Prefix("/clusters/cluster/settings/thresholds").
|
||||
Get("", new(thresholds.IndexAction)).
|
||||
GetPost("/createPopup", new(thresholds.CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(thresholds.UpdatePopupAction)).
|
||||
Post("/delete", new(thresholds.DeleteAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func (this *SelectedReceiversAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
ServerId int64
|
||||
}) {
|
||||
receiversResp, err := this.RPC().MessageReceiverRPC().FindAllMessageReceivers(this.AdminContext(), &pb.FindAllMessageReceiversRequest{
|
||||
receiversResp, err := this.RPC().MessageReceiverRPC().FindAllEnabledMessageReceivers(this.AdminContext(), &pb.FindAllEnabledMessageReceiversRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: params.NodeId,
|
||||
ServerId: params.ServerId,
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package thresholds
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["items"] = nodeconfigs.FindAllNodeValueItemDefinitions()
|
||||
this.Data["operators"] = nodeconfigs.FindAllNodeValueOperatorDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
Item string
|
||||
Param string
|
||||
SumMethod string
|
||||
Operator string
|
||||
Value string
|
||||
Duration int32
|
||||
DurationUnit string
|
||||
Message string
|
||||
NotifyDuration int32
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
if params.ClusterId <= 0 && params.NodeId >= 0 {
|
||||
this.Fail("集群或者节点至少需要填写其中一个参数")
|
||||
}
|
||||
|
||||
valueJSON, err := json.Marshal(params.Value)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
resp, err := this.RPC().NodeThresholdRPC().CreateNodeThreshold(this.AdminContext(), &pb.CreateNodeThresholdRequest{
|
||||
Role: "node",
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: params.NodeId,
|
||||
Item: params.Item,
|
||||
Param: params.Param,
|
||||
Operator: params.Operator,
|
||||
ValueJSON: valueJSON,
|
||||
Message: params.Message,
|
||||
Duration: params.Duration,
|
||||
DurationUnit: params.DurationUnit,
|
||||
SumMethod: params.SumMethod,
|
||||
NotifyDuration: params.NotifyDuration,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
defer this.CreateLogInfo("创建节点阈值 %d", resp.NodeThresholdId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package thresholds
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
// DeleteAction 删除阈值
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
ThresholdId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("删除阈值 %d", params.ThresholdId)
|
||||
|
||||
_, err := this.RPC().NodeThresholdRPC().DeleteNodeThreshold(this.AdminContext(), &pb.DeleteNodeThresholdRequest{NodeThresholdId: params.ThresholdId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package thresholds
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "setting")
|
||||
this.SecondMenu("threshold")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
// 列出所有阈值
|
||||
thresholdsResp, err := this.RPC().NodeThresholdRPC().FindAllEnabledNodeThresholds(this.AdminContext(), &pb.FindAllEnabledNodeThresholdsRequest{
|
||||
Role: "node",
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
thresholdMaps := []maps.Map{}
|
||||
for _, threshold := range thresholdsResp.NodeThresholds {
|
||||
var nodeMap maps.Map = nil
|
||||
if threshold.Node != nil {
|
||||
nodeMap = maps.Map{
|
||||
"id": threshold.Node.Id,
|
||||
"name": threshold.Node.Name,
|
||||
}
|
||||
}
|
||||
|
||||
thresholdMaps = append(thresholdMaps, maps.Map{
|
||||
"id": threshold.Id,
|
||||
"itemName": nodeconfigs.FindNodeValueItemName(threshold.Item),
|
||||
"paramName": nodeconfigs.FindNodeValueItemParamName(threshold.Item, threshold.Param),
|
||||
"operatorName": nodeconfigs.FindNodeValueOperatorName(threshold.Operator),
|
||||
"value": nodeconfigs.UnmarshalNodeValue(threshold.ValueJSON),
|
||||
"sumMethodName": nodeconfigs.FindNodeValueSumMethodName(threshold.SumMethod),
|
||||
"duration": threshold.Duration,
|
||||
"durationUnitName": nodeconfigs.FindNodeValueDurationUnitName(threshold.DurationUnit),
|
||||
"isOn": threshold.IsOn,
|
||||
"node": nodeMap,
|
||||
})
|
||||
}
|
||||
this.Data["thresholds"] = thresholdMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package thresholds
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
ThresholdId int64
|
||||
}) {
|
||||
// 通用参数
|
||||
this.Data["items"] = nodeconfigs.FindAllNodeValueItemDefinitions()
|
||||
this.Data["operators"] = nodeconfigs.FindAllNodeValueOperatorDefinitions()
|
||||
|
||||
// 阈值详情
|
||||
thresholdResp, err := this.RPC().NodeThresholdRPC().FindEnabledNodeThreshold(this.AdminContext(), &pb.FindEnabledNodeThresholdRequest{NodeThresholdId: params.ThresholdId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
threshold := thresholdResp.NodeThreshold
|
||||
if threshold == nil {
|
||||
this.NotFound("nodeThreshold", params.ThresholdId)
|
||||
return
|
||||
}
|
||||
|
||||
valueInterface := new(interface{})
|
||||
err = json.Unmarshal(threshold.ValueJSON, valueInterface)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["threshold"] = maps.Map{
|
||||
"id": threshold.Id,
|
||||
"item": threshold.Item,
|
||||
"param": threshold.Param,
|
||||
"message": threshold.Message,
|
||||
"notifyDuration": threshold.NotifyDuration,
|
||||
"value": nodeconfigs.UnmarshalNodeValue(threshold.ValueJSON),
|
||||
"operator": threshold.Operator,
|
||||
"duration": threshold.Duration,
|
||||
"durationUnit": threshold.DurationUnit,
|
||||
"isOn": threshold.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
ThresholdId int64
|
||||
Item string
|
||||
Param string
|
||||
SumMethod string
|
||||
Operator string
|
||||
Value string
|
||||
Duration int32
|
||||
DurationUnit string
|
||||
Message string
|
||||
NotifyDuration int32
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改节点阈值 %d", params.ThresholdId)
|
||||
|
||||
valueJSON, err := json.Marshal(params.Value)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().NodeThresholdRPC().UpdateNodeThreshold(this.AdminContext(), &pb.UpdateNodeThresholdRequest{
|
||||
NodeThresholdId: params.ThresholdId,
|
||||
Item: params.Item,
|
||||
Param: params.Param,
|
||||
Operator: params.Operator,
|
||||
ValueJSON: valueJSON,
|
||||
Message: params.Message,
|
||||
NotifyDuration: params.NotifyDuration,
|
||||
Duration: params.Duration,
|
||||
DurationUnit: params.DurationUnit,
|
||||
SumMethod: params.SumMethod,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -58,17 +58,17 @@ func (this *UpdateNodeSSHAction) RunGet(params struct {
|
||||
|
||||
// 认证信息
|
||||
grantId := loginParams.GetInt64("grantId")
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledGrant(this.AdminContext(), &pb.FindEnabledGrantRequest{GrantId: grantId})
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
var grantMap maps.Map = nil
|
||||
if grantResp.Grant != nil {
|
||||
if grantResp.NodeGrant != nil {
|
||||
grantMap = maps.Map{
|
||||
"id": grantResp.Grant.Id,
|
||||
"name": grantResp.Grant.Name,
|
||||
"method": grantResp.Grant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.Grant.Method),
|
||||
"id": grantResp.NodeGrant.Id,
|
||||
"name": grantResp.NodeGrant.Name,
|
||||
"method": grantResp.NodeGrant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||
}
|
||||
}
|
||||
this.Data["grant"] = grantMap
|
||||
|
||||
@@ -24,10 +24,10 @@ func NewClusterHelper() *ClusterHelper {
|
||||
return &ClusterHelper{}
|
||||
}
|
||||
|
||||
func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) {
|
||||
func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
|
||||
action := actionPtr.Object()
|
||||
if action.Request.Method != http.MethodGet {
|
||||
return
|
||||
return true
|
||||
}
|
||||
|
||||
action.Data["teaMenu"] = "clusters"
|
||||
@@ -67,6 +67,8 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) {
|
||||
action.Data["leftMenuItems"] = this.createSettingMenu(cluster, secondMenuItem)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 设置菜单
|
||||
@@ -117,10 +119,21 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt
|
||||
"isOn": cluster.DnsDomainId > 0 || len(cluster.DnsName) > 0,
|
||||
})
|
||||
if teaconst.IsPlus {
|
||||
hasThresholds, _ := this.checkThresholds(cluster.Id)
|
||||
items = append(items, maps.Map{
|
||||
"name": "阈值设置",
|
||||
"url": "/clusters/cluster/settings/thresholds?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "threshold",
|
||||
"isOn": hasThresholds,
|
||||
})
|
||||
}
|
||||
if teaconst.IsPlus {
|
||||
hasMessageReceivers, _ := this.checkMessages(cluster.Id)
|
||||
items = append(items, maps.Map{
|
||||
"name": "消息通知",
|
||||
"url": "/clusters/cluster/settings/message?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "message",
|
||||
"isOn": hasMessageReceivers,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -176,3 +189,34 @@ func (this *ClusterHelper) checkFirewallActions(clusterId int64) (bool, error) {
|
||||
}
|
||||
return resp.Count > 0, nil
|
||||
}
|
||||
|
||||
// 检查阈值是否已经设置
|
||||
func (this *ClusterHelper) checkThresholds(clusterId int64) (bool, error) {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
resp, err := rpcClient.NodeThresholdRPC().CountAllEnabledNodeThresholds(rpcClient.Context(0), &pb.CountAllEnabledNodeThresholdsRequest{
|
||||
Role: "node",
|
||||
NodeClusterId: clusterId,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return resp.Count > 0, nil
|
||||
}
|
||||
|
||||
// 检查消息通知是否已经设置
|
||||
func (this *ClusterHelper) checkMessages(clusterId int64) (bool, error) {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
resp, err := rpcClient.MessageReceiverRPC().CountAllEnabledMessageReceivers(rpcClient.Context(0), &pb.CountAllEnabledMessageReceiversRequest{
|
||||
NodeClusterId: clusterId,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return resp.Count > 0, nil
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ func (this *CreateAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "创建SSH认证 %d", createResp.GrantId)
|
||||
defer this.CreateLog(oplogs.LevelInfo, "创建SSH认证 %d", createResp.NodeGrantId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -65,14 +65,14 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
this.Data["grant"] = maps.Map{
|
||||
"id": createResp.GrantId,
|
||||
"id": createResp.NodeGrantId,
|
||||
"name": params.Name,
|
||||
"method": params.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(params.Method),
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "创建SSH认证 %d", createResp.GrantId)
|
||||
defer this.CreateLog(oplogs.LevelInfo, "创建SSH认证 %d", createResp.NodeGrantId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func (this *DeleteAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// 删除
|
||||
_, err = this.RPC().NodeGrantRPC().DisableNodeGrant(this.AdminContext(), &pb.DisableNodeGrantRequest{GrantId: params.GrantId})
|
||||
_, err = this.RPC().NodeGrantRPC().DisableNodeGrant(this.AdminContext(), &pb.DisableNodeGrantRequest{NodeGrantId: params.GrantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
|
||||
@@ -19,19 +19,19 @@ func (this *GrantAction) Init() {
|
||||
func (this *GrantAction) RunGet(params struct {
|
||||
GrantId int64
|
||||
}) {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledGrant(this.AdminContext(), &pb.FindEnabledGrantRequest{GrantId: params.GrantId})
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: params.GrantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.Grant == nil {
|
||||
if grantResp.NodeGrant == nil {
|
||||
this.WriteString("can not find the grant")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO 处理节点专用的认证
|
||||
|
||||
grant := grantResp.Grant
|
||||
grant := grantResp.NodeGrant
|
||||
this.Data["grant"] = maps.Map{
|
||||
"id": grant.Id,
|
||||
"name": grant.Name,
|
||||
|
||||
@@ -15,8 +15,14 @@ func (this *IndexAction) Init() {
|
||||
this.Nav("", "grant", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().NodeGrantRPC().CountAllEnabledNodeGrants(this.AdminContext(), &pb.CountAllEnabledNodeGrantsRequest{})
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Keyword string
|
||||
}) {
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
countResp, err := this.RPC().NodeGrantRPC().CountAllEnabledNodeGrants(this.AdminContext(), &pb.CountAllEnabledNodeGrantsRequest{
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
@@ -25,15 +31,16 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
grantsResp, err := this.RPC().NodeGrantRPC().ListEnabledNodeGrants(this.AdminContext(), &pb.ListEnabledNodeGrantsRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
grantMaps := []maps.Map{}
|
||||
for _, grant := range grantsResp.Grants {
|
||||
for _, grant := range grantsResp.NodeGrants {
|
||||
// 集群数
|
||||
countClustersResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClustersWithGrantId(this.AdminContext(), &pb.CountAllEnabledNodeClustersWithGrantIdRequest{GrantId: grant.Id})
|
||||
if err != nil {
|
||||
@@ -57,6 +64,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
"type": grant.Method,
|
||||
"name": grantutils.FindGrantMethodName(grant.Method),
|
||||
},
|
||||
"username": grant.Username,
|
||||
"countClusters": countClusters,
|
||||
"countNodes": countNodes,
|
||||
})
|
||||
|
||||
@@ -24,6 +24,7 @@ func init() {
|
||||
GetPost("/selectPopup", new(SelectPopupAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(UpdatePopupAction)).
|
||||
GetPost("/test", new(TestAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -23,14 +23,16 @@ func (this *SelectPopupAction) RunGet(params struct{}) {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
grants := grantsResp.Grants
|
||||
grants := grantsResp.NodeGrants
|
||||
grantMaps := []maps.Map{}
|
||||
for _, grant := range grants {
|
||||
grantMaps = append(grantMaps, maps.Map{
|
||||
"id": grant.Id,
|
||||
"name": grant.Name,
|
||||
"method": grant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grant.Method),
|
||||
"id": grant.Id,
|
||||
"name": grant.Name,
|
||||
"method": grant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grant.Method),
|
||||
"username": grant.Username,
|
||||
"description": grant.Description,
|
||||
})
|
||||
}
|
||||
this.Data["grants"] = grantMaps
|
||||
@@ -52,12 +54,12 @@ func (this *SelectPopupAction) RunPost(params struct {
|
||||
this.Success()
|
||||
}
|
||||
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledGrant(this.AdminContext(), &pb.FindEnabledGrantRequest{GrantId: params.GrantId})
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: params.GrantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
grant := grantResp.Grant
|
||||
grant := grantResp.NodeGrant
|
||||
if grant == nil {
|
||||
this.Fail("找不到要使用的认证")
|
||||
}
|
||||
|
||||
78
internal/web/actions/default/clusters/grants/test.go
Normal file
78
internal/web/actions/default/clusters/grants/test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package grants
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"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"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) Init() {
|
||||
this.Nav("", "", "test")
|
||||
}
|
||||
|
||||
func (this *TestAction) RunGet(params struct {
|
||||
GrantId int64
|
||||
}) {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: params.GrantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.NodeGrant == nil {
|
||||
this.WriteString("can not find the grant")
|
||||
return
|
||||
}
|
||||
|
||||
grant := grantResp.NodeGrant
|
||||
this.Data["grant"] = maps.Map{
|
||||
"id": grant.Id,
|
||||
"name": grant.Name,
|
||||
"method": grant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grant.Method),
|
||||
"username": grant.Username,
|
||||
"password": strings.Repeat("*", len(grant.Password)),
|
||||
"privateKey": grant.PrivateKey,
|
||||
"description": grant.Description,
|
||||
"su": grant.Su,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
GrantId int64
|
||||
Host string
|
||||
Port int32
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("host", params.Host).
|
||||
Require("请输入节点主机地址").
|
||||
Field("port", params.Port).
|
||||
Gt(0, "请输入正确的端口号").
|
||||
Lt(65535, "请输入正确的端口号")
|
||||
|
||||
resp, err := this.RPC().NodeGrantRPC().TestNodeGrant(this.AdminContext(), &pb.TestNodeGrantRequest{
|
||||
NodeGrantId: params.GrantId,
|
||||
Host: params.Host,
|
||||
Port: params.Port,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["isOk"] = resp.IsOk
|
||||
this.Data["error"] = resp.Error
|
||||
this.Success()
|
||||
}
|
||||
@@ -22,19 +22,19 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
}) {
|
||||
this.Data["methods"] = grantutils.AllGrantMethods()
|
||||
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledGrant(this.AdminContext(), &pb.FindEnabledGrantRequest{GrantId: params.GrantId})
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: params.GrantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.Grant == nil {
|
||||
if grantResp.NodeGrant == nil {
|
||||
this.WriteString("can not find the grant")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO 处理节点专用的认证
|
||||
|
||||
grant := grantResp.Grant
|
||||
grant := grantResp.NodeGrant
|
||||
this.Data["grant"] = maps.Map{
|
||||
"id": grant.Id,
|
||||
"name": grant.Name,
|
||||
@@ -84,7 +84,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
// TODO 检查grantId是否存在
|
||||
|
||||
_, err := this.RPC().NodeGrantRPC().UpdateNodeGrant(this.AdminContext(), &pb.UpdateNodeGrantRequest{
|
||||
GrantId: params.GrantId,
|
||||
NodeGrantId: params.GrantId,
|
||||
Name: params.Name,
|
||||
Method: params.Method,
|
||||
Username: params.Username,
|
||||
|
||||
@@ -22,18 +22,18 @@ func (this *UpdatePopupAction) RunGet(params struct {
|
||||
}) {
|
||||
this.Data["methods"] = grantutils.AllGrantMethods()
|
||||
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledGrant(this.AdminContext(), &pb.FindEnabledGrantRequest{GrantId: params.GrantId})
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: params.GrantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if grantResp.Grant == nil {
|
||||
if grantResp.NodeGrant == nil {
|
||||
this.WriteString("找不到要操作的对象")
|
||||
return
|
||||
}
|
||||
|
||||
grant := grantResp.Grant
|
||||
grant := grantResp.NodeGrant
|
||||
this.Data["grant"] = maps.Map{
|
||||
"id": grant.Id,
|
||||
"nodeId": grant.NodeId,
|
||||
@@ -82,7 +82,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
|
||||
// 执行修改
|
||||
_, err := this.RPC().NodeGrantRPC().UpdateNodeGrant(this.AdminContext(), &pb.UpdateNodeGrantRequest{
|
||||
GrantId: params.GrantId,
|
||||
NodeGrantId: params.GrantId,
|
||||
Name: params.Name,
|
||||
Method: params.Method,
|
||||
Username: params.Username,
|
||||
|
||||
@@ -24,9 +24,10 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Keyword string
|
||||
SearchType string
|
||||
}) {
|
||||
isSearching := len(params.Keyword) > 0
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["searchType"] = params.SearchType
|
||||
this.Data["isSearching"] = len(params.Keyword) > 0
|
||||
this.Data["isSearching"] = isSearching
|
||||
|
||||
// 搜索节点
|
||||
if params.SearchType == "node" && len(params.Keyword) > 0 {
|
||||
@@ -34,6 +35,23 @@ func (this *IndexAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
// 常用的节点
|
||||
latestClusterMaps := []maps.Map{}
|
||||
if !isSearching {
|
||||
clustersResp, err := this.RPC().NodeClusterRPC().FindLatestNodeClusters(this.AdminContext(), &pb.FindLatestNodeClustersRequest{Size: 6})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, cluster := range clustersResp.NodeClusters {
|
||||
latestClusterMaps = append(latestClusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["latestClusters"] = latestClusterMaps
|
||||
|
||||
// 搜索集群
|
||||
countResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{
|
||||
Keyword: params.Keyword,
|
||||
|
||||
87
internal/web/actions/default/clusters/logs/index.go
Normal file
87
internal/web/actions/default/clusters/logs/index.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
DayFrom string
|
||||
DayTo string
|
||||
Keyword string
|
||||
Level string
|
||||
}) {
|
||||
this.Data["dayFrom"] = params.DayFrom
|
||||
this.Data["dayTo"] = params.DayTo
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["level"] = params.Level
|
||||
|
||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||
NodeId: 0,
|
||||
Role: "node",
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
|
||||
NodeId: 0,
|
||||
Role: "node",
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
|
||||
logs := []maps.Map{}
|
||||
for _, log := range logsResp.NodeLogs {
|
||||
// 节点信息
|
||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: log.NodeId})
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
node := nodeResp.Node
|
||||
if node == nil || node.NodeCluster == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
logs = append(logs, maps.Map{
|
||||
"tag": log.Tag,
|
||||
"description": log.Description,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
|
||||
"level": log.Level,
|
||||
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
|
||||
"count": log.Count,
|
||||
"node": maps.Map{
|
||||
"id": node.Id,
|
||||
"cluster": maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
"name": node.NodeCluster.Name,
|
||||
},
|
||||
"name": node.Name,
|
||||
},
|
||||
})
|
||||
}
|
||||
this.Data["logs"] = logs
|
||||
|
||||
this.Show()
|
||||
}
|
||||
19
internal/web/actions/default/clusters/logs/init.go
Normal file
19
internal/web/actions/default/clusters/logs/init.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package logs
|
||||
|
||||
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.AdminModuleCodeNode)).
|
||||
Data("teaMenu", "clusters").
|
||||
Data("teaSubMenu", "log").
|
||||
Prefix("/clusters/logs").
|
||||
Get("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -77,8 +77,10 @@ func (this *PricesAction) formatBits(bits int64) string {
|
||||
sizeHuman = fmt.Sprintf("%.2fGBPS", float64(bits)/1000/1000/1000)
|
||||
} else if bits < 1_000_000_000_000_000 {
|
||||
sizeHuman = fmt.Sprintf("%.2fTBPS", float64(bits)/1000/1000/1000/1000)
|
||||
} else {
|
||||
} else if bits < 1_000_000_000_000_000_000 {
|
||||
sizeHuman = fmt.Sprintf("%.2fPBPS", float64(bits)/1000/1000/1000/1000/1000)
|
||||
} else {
|
||||
sizeHuman = fmt.Sprintf("%.2fEBPS", float64(bits)/1000/1000/1000/1000/1000/1000)
|
||||
}
|
||||
return sizeHuman
|
||||
}
|
||||
|
||||
@@ -92,5 +92,27 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
this.Data["dailyTrafficStats"] = statMaps
|
||||
}
|
||||
|
||||
// 版本升级
|
||||
this.Data["nodeUpgradeInfo"] = maps.Map{
|
||||
"count": resp.NodeUpgradeInfo.CountNodes,
|
||||
"version": resp.NodeUpgradeInfo.NewVersion,
|
||||
}
|
||||
this.Data["monitorNodeUpgradeInfo"] = maps.Map{
|
||||
"count": resp.MonitorNodeUpgradeInfo.CountNodes,
|
||||
"version": resp.MonitorNodeUpgradeInfo.NewVersion,
|
||||
}
|
||||
this.Data["apiNodeUpgradeInfo"] = maps.Map{
|
||||
"count": resp.ApiNodeUpgradeInfo.CountNodes,
|
||||
"version": resp.ApiNodeUpgradeInfo.NewVersion,
|
||||
}
|
||||
this.Data["userNodeUpgradeInfo"] = maps.Map{
|
||||
"count": resp.UserNodeUpgradeInfo.CountNodes,
|
||||
"version": resp.UserNodeUpgradeInfo.NewVersion,
|
||||
}
|
||||
this.Data["authorityNodeUpgradeInfo"] = maps.Map{
|
||||
"count": resp.AuthorityNodeUpgradeInfo.CountNodes,
|
||||
"version": resp.AuthorityNodeUpgradeInfo.NewVersion,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// MessageResult 和节点消息通讯结果定义
|
||||
type MessageResult struct {
|
||||
NodeId int64 `json:"nodeId"`
|
||||
NodeName string `json:"nodeName"`
|
||||
@@ -17,7 +19,7 @@ type MessageResult struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// 向集群发送命令消息
|
||||
// SendMessageToCluster 向集群发送命令消息
|
||||
func SendMessageToCluster(ctx context.Context, clusterId int64, code string, msg interface{}, timeoutSeconds int32) (results []*MessageResult, err error) {
|
||||
results = []*MessageResult{}
|
||||
|
||||
@@ -153,10 +155,17 @@ func SendMessageToCluster(ctx context.Context, clusterId int64, code string, msg
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
// 对结果进行排序
|
||||
if len(results) > 0 {
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].NodeId < results[j].NodeId
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 向一组节点发送命令消息
|
||||
// SendMessageToNodeIds 向一组节点发送命令消息
|
||||
func SendMessageToNodeIds(ctx context.Context, nodeIds []int64, code string, msg interface{}, timeoutSeconds int32) (results []*MessageResult, err error) {
|
||||
results = []*MessageResult{}
|
||||
if len(nodeIds) == 0 {
|
||||
@@ -321,5 +330,12 @@ func SendMessageToNodeIds(ctx context.Context, nodeIds []int64, code string, msg
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
// 对结果进行排序
|
||||
if len(results) > 0 {
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].NodeId < results[j].NodeId
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 选择证书
|
||||
// SelectPopupAction 选择证书
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
@@ -25,10 +25,12 @@ func (this *SelectPopupAction) Init() {
|
||||
func (this *SelectPopupAction) RunGet(params struct {
|
||||
ViewSize string
|
||||
SelectedCertIds string
|
||||
Keyword string
|
||||
}) {
|
||||
// TODO 支持关键词搜索
|
||||
// TODO 列出常用和最新的证书供用户选择
|
||||
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
// 已经选择的证书
|
||||
selectedCertIds := []string{}
|
||||
if len(params.SelectedCertIds) > 0 {
|
||||
@@ -40,7 +42,9 @@ func (this *SelectPopupAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["viewSize"] = params.ViewSize
|
||||
|
||||
countResp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{})
|
||||
countResp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
@@ -50,8 +54,9 @@ func (this *SelectPopupAction) RunGet(params struct {
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
listResp, err := this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
|
||||
certConfigs := []*sslconfigs.SSLCertConfig{}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net/http"
|
||||
"strconv"
|
||||
strings "strings"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type PurgeAction struct {
|
||||
@@ -53,6 +53,7 @@ func (this *PurgeAction) RunGet(params struct {
|
||||
func (this *PurgeAction) RunPost(params struct {
|
||||
CachePolicyId int64
|
||||
ClusterId int64
|
||||
Type string
|
||||
Keys string
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -96,6 +97,11 @@ func (this *PurgeAction) RunPost(params struct {
|
||||
CachePolicyJSON: cachePolicyJSON,
|
||||
Keys: realKeys,
|
||||
}
|
||||
if params.Type == "prefix" {
|
||||
msg.Type = messageconfigs.PurgeCacheMessageTypeDir
|
||||
} else {
|
||||
msg.Type = messageconfigs.PurgeCacheMessageTypeFile
|
||||
}
|
||||
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodePurgeCache, msg, 10)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -63,8 +63,13 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
RefsJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改缓存策略:%d", params.CachePolicyId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入策略名称")
|
||||
@@ -104,6 +109,22 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 校验缓存条件
|
||||
refs := []*serverconfigs.HTTPCacheRef{}
|
||||
if len(params.RefsJSON) > 0 {
|
||||
err = json.Unmarshal(params.RefsJSON, &refs)
|
||||
if err != nil {
|
||||
this.Fail("缓存条件解析失败:" + err.Error())
|
||||
}
|
||||
for _, ref := range refs {
|
||||
err = ref.Init()
|
||||
if err != nil {
|
||||
this.Fail("缓存条件校验失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicy(this.AdminContext(), &pb.UpdateHTTPCachePolicyRequest{
|
||||
HttpCachePolicyId: params.CachePolicyId,
|
||||
IsOn: params.IsOn,
|
||||
@@ -120,8 +141,15 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改缓存策略:%d", params.CachePolicyId)
|
||||
// 修改缓存条件
|
||||
_, err = this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicyRefs(this.AdminContext(), &pb.UpdateHTTPCachePolicyRefsRequest{
|
||||
HttpCachePolicyId: params.CachePolicyId,
|
||||
RefsJSON: params.RefsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
24
internal/web/actions/default/servers/fixLog.go
Normal file
24
internal/web/actions/default/servers/fixLog.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package servers
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type FixLogAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *FixLogAction) RunPost(params struct {
|
||||
LogId int64
|
||||
}) {
|
||||
_, err := this.RPC().NodeLogRPC().FixNodeLog(this.AdminContext(), &pb.FixNodeLogRequest{NodeLogId: params.LogId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -4,9 +4,11 @@ import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -30,10 +32,29 @@ func (this *IndexAction) RunGet(params struct {
|
||||
this.Data["auditingFlag"] = params.AuditingFlag
|
||||
this.Data["checkDNS"] = params.CheckDNS
|
||||
|
||||
isSearching := params.AuditingFlag == 1 || params.ClusterId > 0 || params.GroupId > 0 || len(params.Keyword) > 0
|
||||
|
||||
if params.AuditingFlag > 0 {
|
||||
this.Data["firstMenuItem"] = "auditing"
|
||||
}
|
||||
|
||||
// 常用的服务
|
||||
latestServerMaps := []maps.Map{}
|
||||
if !isSearching {
|
||||
serversResp, err := this.RPC().ServerRPC().FindLatestServers(this.AdminContext(), &pb.FindLatestServersRequest{Size: 6})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, server := range serversResp.Servers {
|
||||
latestServerMaps = append(latestServerMaps, maps.Map{
|
||||
"id": server.Id,
|
||||
"name": server.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["latestServers"] = latestServerMaps
|
||||
|
||||
// 审核中的数量
|
||||
countAuditingResp, err := this.RPC().ServerRPC().CountAllEnabledServersMatch(this.AdminContext(), &pb.CountAllEnabledServersMatchRequest{
|
||||
AuditingFlag: 1,
|
||||
@@ -231,5 +252,48 @@ func (this *IndexAction) RunGet(params struct {
|
||||
// 是否有用户管理权限
|
||||
this.Data["canVisitUser"] = configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeUser)
|
||||
|
||||
// 显示服务相关的日志
|
||||
errorLogsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
|
||||
NodeId: 0,
|
||||
Role: "node",
|
||||
Offset: 0,
|
||||
Size: 10,
|
||||
Level: "error",
|
||||
FixedState: int32(configutils.BoolStateNo),
|
||||
AllServers: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
errorLogMaps := []maps.Map{}
|
||||
for _, errorLog := range errorLogsResp.NodeLogs {
|
||||
serverResp, err := this.RPC().ServerRPC().FindEnabledUserServerBasic(this.AdminContext(), &pb.FindEnabledUserServerBasicRequest{ServerId: errorLog.ServerId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
server := serverResp.Server
|
||||
if server == nil {
|
||||
// 设置为已修复
|
||||
_, err = this.RPC().NodeLogRPC().FixNodeLog(this.AdminContext(), &pb.FixNodeLogRequest{NodeLogId: errorLog.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
errorLogMaps = append(errorLogMaps, maps.Map{
|
||||
"id": errorLog.Id,
|
||||
"description": errorLog.Description,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", errorLog.CreatedAt),
|
||||
"serverId": errorLog.ServerId,
|
||||
"serverName": server.Name,
|
||||
})
|
||||
}
|
||||
this.Data["errorLogs"] = errorLogMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ func init() {
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/create", new(CreateAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Post("/fixLog", new(FixLogAction)).
|
||||
|
||||
GetPost("/addPortPopup", new(AddPortPopupAction)).
|
||||
GetPost("/addServerNamePopup", new(AddServerNamePopupAction)).
|
||||
|
||||
@@ -24,6 +24,16 @@ func (this *IndexAction) RunGet(params struct {
|
||||
this.Data["serverId"] = params.ServerId
|
||||
this.Data["requestId"] = params.RequestId
|
||||
|
||||
// 记录最近使用
|
||||
_, err := this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
||||
ItemType: "server",
|
||||
ItemId: params.ServerId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
|
||||
@@ -60,13 +60,17 @@ func (this *IndexAction) RunPost(params struct {
|
||||
// 日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改Web %d 的缓存设置", params.WebId)
|
||||
|
||||
// TODO 校验配置
|
||||
// 校验配置
|
||||
cacheConfig := &serverconfigs.HTTPCacheConfig{}
|
||||
err := json.Unmarshal(params.CacheJSON, cacheConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
err = cacheConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("检查配置失败:" + err.Error())
|
||||
}
|
||||
|
||||
// 去除不必要的部分
|
||||
for _, cacheRef := range cacheConfig.CacheRefs {
|
||||
|
||||
@@ -14,9 +14,10 @@ type CondJSComponent struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Component string `json:"component"`
|
||||
IsRequest bool `json:"isRequest"`
|
||||
}
|
||||
|
||||
// 读取所有可用的条件
|
||||
// ReadAllAvailableCondTypes 读取所有可用的条件
|
||||
func ReadAllAvailableCondTypes() []*CondJSComponent {
|
||||
result := []*CondJSComponent{}
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package fastcgi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"net"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Address string
|
||||
ParamsJSON []byte
|
||||
ReadTimeout int64
|
||||
PoolSize int32
|
||||
PathInfoPattern string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var fastcgiId = int64(0)
|
||||
defer func() {
|
||||
if fastcgiId > 0 {
|
||||
this.CreateLogInfo("创建Fastcgi %d", fastcgiId)
|
||||
} else {
|
||||
this.CreateLogInfo("创建Fastcgi")
|
||||
}
|
||||
}()
|
||||
|
||||
params.Must.
|
||||
Field("address", params.Address).
|
||||
Require("请输入Fastcgi地址")
|
||||
|
||||
_, _, err := net.SplitHostPort(params.Address)
|
||||
if err != nil {
|
||||
this.FailField("address", "请输入正确的Fastcgi地址")
|
||||
}
|
||||
|
||||
readTimeoutJSON, err := json.Marshal(&shared.TimeDuration{
|
||||
Count: params.ReadTimeout,
|
||||
Unit: "second",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().HTTPFastcgiRPC().CreateHTTPFastcgi(this.AdminContext(), &pb.CreateHTTPFastcgiRequest{
|
||||
IsOn: params.IsOn,
|
||||
Address: params.Address,
|
||||
ParamsJSON: params.ParamsJSON,
|
||||
ReadTimeoutJSON: readTimeoutJSON,
|
||||
ConnTimeoutJSON: nil, // TODO 将来支持
|
||||
PoolSize: params.PoolSize,
|
||||
PathInfoPattern: params.PathInfoPattern,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
fastcgiId = createResp.HttpFastcgiId
|
||||
|
||||
configResp, err := this.RPC().HTTPFastcgiRPC().FindEnabledHTTPFastcgiConfig(this.AdminContext(), &pb.FindEnabledHTTPFastcgiConfigRequest{HttpFastcgiId: fastcgiId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
configJSON := configResp.HttpFastcgiJSON
|
||||
config := &serverconfigs.HTTPFastcgiConfig{}
|
||||
err = json.Unmarshal(configJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["fastcgi"] = config
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package fastcgi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "index")
|
||||
this.SecondMenu("fastcgi")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ServerId int64
|
||||
}) {
|
||||
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["webId"] = webConfig.Id
|
||||
this.Data["fastcgiRef"] = webConfig.FastcgiRef
|
||||
this.Data["fastcgiConfigs"] = webConfig.FastcgiList
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
WebId int64
|
||||
FastcgiRefJSON []byte
|
||||
FastcgiJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改Web %d 的Fastcgi设置", params.WebId)
|
||||
|
||||
// TODO 检查配置
|
||||
|
||||
fastcgiRef := &serverconfigs.HTTPFastcgiRef{}
|
||||
err := json.Unmarshal(params.FastcgiRefJSON, fastcgiRef)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
fastcgiRefJSON, err := json.Marshal(fastcgiRef)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebFastcgi(this.AdminContext(), &pb.UpdateHTTPWebFastcgiRequest{
|
||||
WebId: params.WebId,
|
||||
FastcgiJSON: fastcgiRefJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package fastcgi
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"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(serverutils.NewServerHelper()).
|
||||
Prefix("/servers/server/settings/fastcgi").
|
||||
GetPost("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(UpdatePopupAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package fastcgi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"net"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
FastcgiId int64
|
||||
}) {
|
||||
configResp, err := this.RPC().HTTPFastcgiRPC().FindEnabledHTTPFastcgiConfig(this.AdminContext(), &pb.FindEnabledHTTPFastcgiConfigRequest{HttpFastcgiId: params.FastcgiId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
configJSON := configResp.HttpFastcgiJSON
|
||||
config := &serverconfigs.HTTPFastcgiConfig{}
|
||||
err = json.Unmarshal(configJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["fastcgi"] = config
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
FastcgiId int64
|
||||
Address string
|
||||
ParamsJSON []byte
|
||||
ReadTimeout int64
|
||||
PoolSize int32
|
||||
PathInfoPattern string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改Fastcgi %d", params.FastcgiId)
|
||||
|
||||
params.Must.
|
||||
Field("address", params.Address).
|
||||
Require("请输入Fastcgi地址")
|
||||
|
||||
_, _, err := net.SplitHostPort(params.Address)
|
||||
if err != nil {
|
||||
this.FailField("address", "请输入正确的Fastcgi地址")
|
||||
}
|
||||
|
||||
readTimeoutJSON, err := json.Marshal(&shared.TimeDuration{
|
||||
Count: params.ReadTimeout,
|
||||
Unit: "second",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPFastcgiRPC().UpdateHTTPFastcgi(this.AdminContext(), &pb.UpdateHTTPFastcgiRequest{
|
||||
HttpFastcgiId: params.FastcgiId,
|
||||
IsOn: params.IsOn,
|
||||
Address: params.Address,
|
||||
ParamsJSON: params.ParamsJSON,
|
||||
ReadTimeoutJSON: readTimeoutJSON,
|
||||
ConnTimeoutJSON: nil, // TODO 将来支持
|
||||
PoolSize: params.PoolSize,
|
||||
PathInfoPattern: params.PathInfoPattern,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
configResp, err := this.RPC().HTTPFastcgiRPC().FindEnabledHTTPFastcgiConfig(this.AdminContext(), &pb.FindEnabledHTTPFastcgiConfigRequest{HttpFastcgiId: params.FastcgiId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
configJSON := configResp.HttpFastcgiJSON
|
||||
config := &serverconfigs.HTTPFastcgiConfig{}
|
||||
err = json.Unmarshal(configJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["fastcgi"] = config
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -40,12 +40,12 @@ func (this *IndexAction) RunGet(params struct {
|
||||
IsOn: true,
|
||||
}
|
||||
if gzipId > 0 {
|
||||
resp, err := this.RPC().HTTPGzipRPC().FindEnabledHTTPGzipConfig(this.AdminContext(), &pb.FindEnabledGzipConfigRequest{GzipId: gzipId})
|
||||
resp, err := this.RPC().HTTPGzipRPC().FindEnabledHTTPGzipConfig(this.AdminContext(), &pb.FindEnabledGzipConfigRequest{HttpGzipId: gzipId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(resp.GzipJSON, gzipConfig)
|
||||
err = json.Unmarshal(resp.HttpGzipJSON, gzipConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
@@ -111,11 +111,11 @@ func (this *IndexAction) RunPost(params struct {
|
||||
|
||||
if params.GzipId > 0 {
|
||||
_, err := this.RPC().HTTPGzipRPC().UpdateHTTPGzip(this.AdminContext(), &pb.UpdateHTTPGzipRequest{
|
||||
GzipId: params.GzipId,
|
||||
Level: types.Int32(params.Level),
|
||||
MinLength: minLength,
|
||||
MaxLength: maxLength,
|
||||
CondsJSON: params.CondsJSON,
|
||||
HttpGzipId: params.GzipId,
|
||||
Level: types.Int32(params.Level),
|
||||
MinLength: minLength,
|
||||
MaxLength: maxLength,
|
||||
CondsJSON: params.CondsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -132,7 +132,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
gzipRef.GzipId = resp.GzipId
|
||||
gzipRef.GzipId = resp.HttpGzipId
|
||||
}
|
||||
|
||||
gzipRefJSON, err := json.Marshal(gzipRef)
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -76,6 +78,24 @@ func (this *IndexAction) RunPost(params struct {
|
||||
this.Fail("端口地址解析失败:" + err.Error())
|
||||
}
|
||||
|
||||
// 检查端口地址是否正确
|
||||
for _, addr := range addresses {
|
||||
err = addr.Init()
|
||||
if err != nil {
|
||||
this.Fail("绑定端口校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
if regexp.MustCompile(`^\d+$`).MatchString(addr.PortRange) {
|
||||
port := types.Int(addr.PortRange)
|
||||
if port > 65535 {
|
||||
this.Fail("绑定的端口地址不能大于65535")
|
||||
}
|
||||
if port == 443 {
|
||||
this.Fail("端口443通常是HTTPS的端口,不能用在HTTP上")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
server, _, isOk := serverutils.FindServer(this.Parent(), params.ServerId)
|
||||
if !isOk {
|
||||
return
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -87,7 +88,23 @@ func (this *IndexAction) RunPost(params struct {
|
||||
this.Fail("端口地址解析失败:" + err.Error())
|
||||
}
|
||||
|
||||
// TODO 校验addresses
|
||||
// 检查端口地址是否正确
|
||||
for _, addr := range addresses {
|
||||
err = addr.Init()
|
||||
if err != nil {
|
||||
this.Fail("绑定端口校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
if regexp.MustCompile(`^\d+$`).MatchString(addr.PortRange) {
|
||||
port := types.Int(addr.PortRange)
|
||||
if port > 65535 {
|
||||
this.Fail("绑定的端口地址不能大于65535")
|
||||
}
|
||||
if port == 80 {
|
||||
this.Fail("端口80通常是HTTP的端口,不能用在HTTPS上")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 校验SSL
|
||||
var sslPolicyId = int64(0)
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// 服务基本信息设置
|
||||
// IndexAction 服务基本信息设置
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
@@ -102,10 +102,20 @@ func (this *IndexAction) RunGet(params struct {
|
||||
typeName := serverType.GetString("name")
|
||||
this.Data["typeName"] = typeName
|
||||
|
||||
// 记录最近使用
|
||||
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
||||
ItemType: "server",
|
||||
ItemId: params.ServerId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
// 保存
|
||||
// RunPost 保存
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ServerId int64
|
||||
Name string
|
||||
|
||||
@@ -57,13 +57,17 @@ func (this *IndexAction) RunPost(params struct {
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改Web %d 的缓存设置", params.WebId)
|
||||
|
||||
// TODO 校验配置
|
||||
// 校验配置
|
||||
cacheConfig := &serverconfigs.HTTPCacheConfig{}
|
||||
err := json.Unmarshal(params.CacheJSON, cacheConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
err = cacheConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("检查配置失败:" + err.Error())
|
||||
}
|
||||
|
||||
// 去除不必要的部分
|
||||
for _, cacheRef := range cacheConfig.CacheRefs {
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package fastcgi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
LocationId int64
|
||||
}) {
|
||||
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithLocationId(this.AdminContext(), params.LocationId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["webId"] = webConfig.Id
|
||||
this.Data["fastcgiRef"] = webConfig.FastcgiRef
|
||||
this.Data["fastcgiConfigs"] = webConfig.FastcgiList
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
WebId int64
|
||||
FastcgiRefJSON []byte
|
||||
FastcgiJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改Web %d 的Fastcgi设置", params.WebId)
|
||||
|
||||
// TODO 检查配置
|
||||
|
||||
fastcgiRef := &serverconfigs.HTTPFastcgiRef{}
|
||||
err := json.Unmarshal(params.FastcgiRefJSON, fastcgiRef)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
fastcgiRefJSON, err := json.Marshal(fastcgiRef)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebFastcgi(this.AdminContext(), &pb.UpdateHTTPWebFastcgiRequest{
|
||||
WebId: params.WebId,
|
||||
FastcgiJSON: fastcgiRefJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package fastcgi
|
||||
|
||||
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("tinyMenuItem", "fastcgi").
|
||||
Prefix("/servers/server/settings/locations/fastcgi").
|
||||
GetPost("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -39,12 +39,12 @@ func (this *IndexAction) RunGet(params struct {
|
||||
IsOn: true,
|
||||
}
|
||||
if gzipId > 0 {
|
||||
resp, err := this.RPC().HTTPGzipRPC().FindEnabledHTTPGzipConfig(this.AdminContext(), &pb.FindEnabledGzipConfigRequest{GzipId: gzipId})
|
||||
resp, err := this.RPC().HTTPGzipRPC().FindEnabledHTTPGzipConfig(this.AdminContext(), &pb.FindEnabledGzipConfigRequest{HttpGzipId: gzipId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(resp.GzipJSON, gzipConfig)
|
||||
err = json.Unmarshal(resp.HttpGzipJSON, gzipConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
@@ -109,10 +109,10 @@ func (this *IndexAction) RunPost(params struct {
|
||||
|
||||
if params.GzipId > 0 {
|
||||
_, err := this.RPC().HTTPGzipRPC().UpdateHTTPGzip(this.AdminContext(), &pb.UpdateHTTPGzipRequest{
|
||||
GzipId: params.GzipId,
|
||||
Level: types.Int32(params.Level),
|
||||
MinLength: minLength,
|
||||
MaxLength: maxLength,
|
||||
HttpGzipId: params.GzipId,
|
||||
Level: types.Int32(params.Level),
|
||||
MinLength: minLength,
|
||||
MaxLength: maxLength,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -128,7 +128,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
gzipId := resp.GzipId
|
||||
gzipId := resp.HttpGzipId
|
||||
gzipRef.GzipId = gzipId
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package locations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -24,11 +28,36 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["webId"] = webConfig.Id
|
||||
|
||||
locationMaps := []maps.Map{}
|
||||
if webConfig.Locations != nil {
|
||||
this.Data["locations"] = webConfig.Locations
|
||||
} else {
|
||||
this.Data["locations"] = []interface{}{}
|
||||
for _, location := range webConfig.Locations {
|
||||
err := location.ExtractPattern()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
jsonData, err := json.Marshal(location)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
m := maps.Map{}
|
||||
err = json.Unmarshal(jsonData, &m)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
pieces := strings.Split(location.Pattern, " ")
|
||||
if len(pieces) == 2 {
|
||||
m["pattern"] = pieces[1]
|
||||
m["patternTypeName"] = serverconfigs.FindLocationPatternTypeName(location.PatternType())
|
||||
} else {
|
||||
m["pattern"] = location.Pattern
|
||||
m["patternTypeName"] = serverconfigs.FindLocationPatternTypeName(serverconfigs.HTTPLocationPatternTypePrefix)
|
||||
}
|
||||
locationMaps = append(locationMaps, m)
|
||||
}
|
||||
}
|
||||
this.Data["locations"] = locationMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -149,6 +149,12 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
|
||||
"isActive": secondMenuItem == "websocket",
|
||||
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.WebsocketRef != nil && locationConfig.Web.WebsocketRef.IsPrior,
|
||||
})
|
||||
menuItems = append(menuItems, maps.Map{
|
||||
"name": "Fastcgi",
|
||||
"url": "/servers/server/settings/locations/fastcgi?serverId=" + serverIdString + "&locationId=" + locationIdString,
|
||||
"isActive": secondMenuItem == "fastcgi",
|
||||
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.FastcgiRef != nil && locationConfig.Web.FastcgiRef.IsPrior,
|
||||
})
|
||||
|
||||
return menuItems
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net/url"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
@@ -27,6 +28,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
BeforeURL string
|
||||
AfterURL string
|
||||
MatchPrefix bool
|
||||
MatchRegexp bool
|
||||
KeepRequestURI bool
|
||||
|
||||
Status int
|
||||
@@ -39,7 +41,12 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Require("请填写跳转前的URL")
|
||||
|
||||
// 校验格式
|
||||
{
|
||||
if params.MatchRegexp {
|
||||
_, err := regexp.Compile(params.BeforeURL)
|
||||
if err != nil {
|
||||
this.Fail("跳转前URL正则表达式错误:" + err.Error())
|
||||
}
|
||||
} else {
|
||||
u, err := url.Parse(params.BeforeURL)
|
||||
if err != nil {
|
||||
this.FailField("beforeURL", "请输入正确的跳转前URL")
|
||||
@@ -56,7 +63,9 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Require("请填写跳转后URL")
|
||||
|
||||
// 校验格式
|
||||
{
|
||||
if params.MatchRegexp {
|
||||
// 正则表达式情况下不做校验
|
||||
} else {
|
||||
u, err := url.Parse(params.AfterURL)
|
||||
if err != nil {
|
||||
this.FailField("afterURL", "请输入正确的跳转后URL")
|
||||
@@ -76,6 +85,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
"beforeURL": params.BeforeURL,
|
||||
"afterURL": params.AfterURL,
|
||||
"matchPrefix": params.MatchPrefix,
|
||||
"matchRegexp": params.MatchRegexp,
|
||||
"keepRequestURI": params.KeepRequestURI,
|
||||
"isOn": true,
|
||||
}
|
||||
|
||||
@@ -146,5 +146,15 @@ func (this *IndexAction) RunGet(params struct {
|
||||
this.Data["provinceStats"] = provinceStatMaps
|
||||
this.Data["cityStats"] = cityStatMaps
|
||||
|
||||
// 记录最近使用
|
||||
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
||||
ItemType: "server",
|
||||
ItemId: params.ServerId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -311,6 +311,12 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
|
||||
"isActive": secondMenuItem == "websocket",
|
||||
"isOn": serverConfig.Web != nil && serverConfig.Web.WebsocketRef != nil && serverConfig.Web.WebsocketRef.IsOn,
|
||||
})
|
||||
menuItems = append(menuItems, maps.Map{
|
||||
"name": "Fastcgi",
|
||||
"url": "/servers/server/settings/fastcgi?serverId=" + serverIdString,
|
||||
"isActive": secondMenuItem == "fastcgi",
|
||||
"isOn": serverConfig.Web != nil && serverConfig.Web.FastcgiRef != nil && serverConfig.Web.FastcgiRef.IsOn,
|
||||
})
|
||||
} else if serverConfig.IsTCPFamily() {
|
||||
menuItems = append(menuItems, maps.Map{
|
||||
"name": "TCP",
|
||||
|
||||
@@ -107,6 +107,7 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
|
||||
}
|
||||
action.Data["teaShowOpenSourceInfo"] = config.ShowOpenSourceInfo
|
||||
action.Data["teaIsSuper"] = false
|
||||
action.Data["teaIsPlus"] = teaconst.IsPlus
|
||||
action.Data["teaDemoEnabled"] = teaconst.IsDemo
|
||||
action.Data["teaShowFinance"] = configloaders.ShowFinance()
|
||||
if !action.Data.Has("teaSubMenu") {
|
||||
@@ -180,6 +181,11 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
||||
"subtitle": "集群列表",
|
||||
"icon": "cloud",
|
||||
"subItems": []maps.Map{
|
||||
{
|
||||
"name": "节点日志",
|
||||
"url": "/clusters/logs",
|
||||
"code": "log",
|
||||
},
|
||||
{
|
||||
"name": "SSH认证",
|
||||
"url": "/clusters/grants",
|
||||
@@ -222,6 +228,7 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
||||
"module": configloaders.AdminModuleCodeFinance,
|
||||
"name": "财务管理",
|
||||
"icon": "yen sign",
|
||||
"isOn": teaconst.IsPlus,
|
||||
},
|
||||
{
|
||||
"code": "admins",
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/logs"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/regions"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/regions/items"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/tasks"
|
||||
@@ -48,6 +49,7 @@ import (
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/charset"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/dns"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/fastcgi"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/gzip"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/headers"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/http"
|
||||
@@ -57,6 +59,7 @@ import (
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/accessLog"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/cache"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/charset"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/fastcgi"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/gzip"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/headers"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/http"
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
Vue.component("http-access-log-box", {
|
||||
props: ["v-access-log"],
|
||||
data: function () {
|
||||
let accessLog = this.vAccessLog
|
||||
if (accessLog.header != null && accessLog.header.Upgrade != null && accessLog.header.Upgrade.values != null && accessLog.header.Upgrade.values.$contains("websocket")) {
|
||||
if (accessLog.scheme == "http") {
|
||||
accessLog.scheme = "ws"
|
||||
} else if (accessLog.scheme == "https") {
|
||||
accessLog.scheme = "wss"
|
||||
}
|
||||
}
|
||||
return {
|
||||
accessLog: this.vAccessLog
|
||||
accessLog: accessLog
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -40,7 +48,7 @@ Vue.component("http-access-log-box", {
|
||||
}
|
||||
},
|
||||
template: `<div :style="{'color': (accessLog.status >= 400) ? '#dc143c' : ''}" ref="box">
|
||||
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> {{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] <em>"{{accessLog.requestMethod}} {{accessLog.scheme}}://{{accessLog.host}}{{accessLog.requestURI}} <a :href="accessLog.scheme + '://' + accessLog.host + accessLog.requestURI" target="_blank" title="新窗口打开" class="disabled"><i class="external icon tiny"></i> </a> {{accessLog.proto}}" </em> {{accessLog.status}} <span v-if="accessLog.attrs != null && accessLog.attrs['cache_cached'] == '1'">[cached]</span> <span v-if="accessLog.attrs != null && accessLog.attrs['waf.action'] != null && accessLog.attrs['waf.action'].length > 0">[waf {{accessLog.attrs['waf.action']}}]</span> - 耗时:{{formatCost(accessLog.requestTime)}} ms
|
||||
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> {{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] <em>"{{accessLog.requestMethod}} {{accessLog.scheme}}://{{accessLog.host}}{{accessLog.requestURI}} <a :href="accessLog.scheme + '://' + accessLog.host + accessLog.requestURI" target="_blank" title="新窗口打开" class="disabled"><i class="external icon tiny"></i> </a> {{accessLog.proto}}" </em> {{accessLog.status}} <code-label v-if="accessLog.attrs != null && accessLog.attrs['cache.status'] == 'HIT'">cache hit</code-label> <code-label v-if="accessLog.attrs != null && accessLog.attrs['waf.action'] != null && accessLog.attrs['waf.action'].length > 0">waf {{accessLog.attrs['waf.action']}}</code-label> - 耗时:{{formatCost(accessLog.requestTime)}} ms
|
||||
<a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>
|
||||
</div>`
|
||||
})
|
||||
@@ -6,6 +6,7 @@ Vue.component("http-cache-config-box", {
|
||||
cacheConfig = {
|
||||
isPrior: false,
|
||||
isOn: false,
|
||||
addStatusHeader: true,
|
||||
cacheRefs: []
|
||||
}
|
||||
}
|
||||
@@ -105,13 +106,22 @@ Vue.component("http-cache-config-box", {
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody v-show="isOn()">
|
||||
<tr>
|
||||
<td>自动添加X-Cache Header</td>
|
||||
<td>
|
||||
<checkbox v-model="cacheConfig.addStatusHeader"></checkbox>
|
||||
<p class="comment">选中后自动在响应Header中增加<code-label>X-Cache: BYPASS|MISS|HIT</code-label>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div v-show="isOn()">
|
||||
<table class="ui table selectable celled" v-show="cacheConfig.cacheRefs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>条件</th>
|
||||
<th>缓存条件</th>
|
||||
<th class="width10">缓存时间</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
|
||||
@@ -13,7 +13,8 @@ Vue.component("http-cache-ref-box", {
|
||||
skipCacheControlValues: ["private", "no-cache", "no-store"],
|
||||
skipSetCookie: true,
|
||||
enableRequestCachePragma: false,
|
||||
conds: null
|
||||
conds: null,
|
||||
allowChunkedEncoding: true
|
||||
}
|
||||
}
|
||||
if (ref.life == null) {
|
||||
@@ -43,7 +44,7 @@ Vue.component("http-cache-ref-box", {
|
||||
},
|
||||
template: `<tbody>
|
||||
<tr>
|
||||
<td class="title">匹配条件 *</td>
|
||||
<td class="title">匹配条件分组 *</td>
|
||||
<td>
|
||||
<http-request-conds-box :v-conds="ref.conds" @change="changeConds"></http-request-conds-box>
|
||||
|
||||
@@ -72,6 +73,13 @@ Vue.component("http-cache-ref-box", {
|
||||
<size-capacity-box :v-value="ref.maxSize" @change="changeMaxSize"></size-capacity-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="moreOptionsVisible">
|
||||
<td>支持分片内容</td>
|
||||
<td>
|
||||
<checkbox name="allowChunkedEncoding" value="1" v-model="ref.allowChunkedEncoding"></checkbox>
|
||||
<p class="comment">选中后,Gzip和Chunked内容可以直接缓存,无需检查内容长度。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="moreOptionsVisible">
|
||||
<td>状态码列表</td>
|
||||
<td>
|
||||
|
||||
58
web/public/js/components/server/http-cache-refs-box.js
Normal file
58
web/public/js/components/server/http-cache-refs-box.js
Normal file
@@ -0,0 +1,58 @@
|
||||
Vue.component("http-cache-refs-box", {
|
||||
props: ["v-cache-refs"],
|
||||
data: function () {
|
||||
let refs = this.vCacheRefs
|
||||
if (refs == null) {
|
||||
refs = []
|
||||
}
|
||||
return {
|
||||
refs: refs
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
timeUnitName: function (unit) {
|
||||
switch (unit) {
|
||||
case "ms":
|
||||
return "毫秒"
|
||||
case "second":
|
||||
return "秒"
|
||||
case "minute":
|
||||
return "分钟"
|
||||
case "hour":
|
||||
return "小时"
|
||||
case "day":
|
||||
return "天"
|
||||
case "week":
|
||||
return "周 "
|
||||
}
|
||||
return unit
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="refsJSON" :value="JSON.stringify(refs)"/>
|
||||
|
||||
<p class="comment" v-if="refs.length == 0">暂时还没有缓存条件。</p>
|
||||
<div v-show="refs.length > 0">
|
||||
<table class="ui table selectable celled">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>缓存条件</th>
|
||||
<th class="width10">缓存时间</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
<tr v-for="(cacheRef, index) in refs">
|
||||
<td>
|
||||
<http-request-conds-view :v-conds="cacheRef.conds"></http-request-conds-view>
|
||||
</td>
|
||||
<td>{{cacheRef.life.count}} {{timeUnitName(cacheRef.life.unit)}}</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="updateRef(index, cacheRef)">修改</a>
|
||||
<a href="" @click.prevent="removeRef(index)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="margin"></div>
|
||||
</div>`
|
||||
})
|
||||
105
web/public/js/components/server/http-cache-refs-config-box.js
Normal file
105
web/public/js/components/server/http-cache-refs-config-box.js
Normal file
@@ -0,0 +1,105 @@
|
||||
Vue.component("http-cache-refs-config-box", {
|
||||
props: ["v-cache-refs"],
|
||||
data: function () {
|
||||
let refs = this.vCacheRefs
|
||||
if (refs == null) {
|
||||
refs = []
|
||||
}
|
||||
return {
|
||||
refs: refs
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addRef: function () {
|
||||
window.UPDATING_CACHE_REF = null
|
||||
|
||||
let width = window.innerWidth
|
||||
if (width > 1024) {
|
||||
width = 1024
|
||||
}
|
||||
let height = window.innerHeight
|
||||
if (height > 500) {
|
||||
height = 500
|
||||
}
|
||||
let that = this
|
||||
teaweb.popup("/servers/server/settings/cache/createPopup", {
|
||||
width: width + "px",
|
||||
height: height + "px",
|
||||
callback: function (resp) {
|
||||
that.refs.push(resp.data.cacheRef)
|
||||
}
|
||||
})
|
||||
},
|
||||
updateRef: function (index, cacheRef) {
|
||||
window.UPDATING_CACHE_REF = cacheRef
|
||||
|
||||
let width = window.innerWidth
|
||||
if (width > 1024) {
|
||||
width = 1024
|
||||
}
|
||||
let height = window.innerHeight
|
||||
if (height > 500) {
|
||||
height = 500
|
||||
}
|
||||
let that = this
|
||||
teaweb.popup("/servers/server/settings/cache/createPopup", {
|
||||
width: width + "px",
|
||||
height: height + "px",
|
||||
callback: function (resp) {
|
||||
Vue.set(that.refs, index, resp.data.cacheRef)
|
||||
}
|
||||
})
|
||||
},
|
||||
removeRef: function (index) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此缓存设置吗?", function () {
|
||||
that.refs.$remove(index)
|
||||
})
|
||||
},
|
||||
timeUnitName: function (unit) {
|
||||
switch (unit) {
|
||||
case "ms":
|
||||
return "毫秒"
|
||||
case "second":
|
||||
return "秒"
|
||||
case "minute":
|
||||
return "分钟"
|
||||
case "hour":
|
||||
return "小时"
|
||||
case "day":
|
||||
return "天"
|
||||
case "week":
|
||||
return "周 "
|
||||
}
|
||||
return unit
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="refsJSON" :value="JSON.stringify(refs)"/>
|
||||
|
||||
<div>
|
||||
<table class="ui table selectable celled" v-show="refs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>缓存条件</th>
|
||||
<th class="width10">缓存时间</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
<tr v-for="(cacheRef, index) in refs">
|
||||
<td>
|
||||
<http-request-conds-view :v-conds="cacheRef.conds"></http-request-conds-view>
|
||||
</td>
|
||||
<td>{{cacheRef.life.count}} {{timeUnitName(cacheRef.life.unit)}}</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="updateRef(index, cacheRef)">修改</a>
|
||||
<a href="" @click.prevent="removeRef(index)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
<button class="ui button tiny" @click.prevent="addRef">+添加缓存设置</button>
|
||||
</div>
|
||||
<div class="margin"></div>
|
||||
</div>`
|
||||
})
|
||||
@@ -102,6 +102,75 @@ Vue.component("http-cond-url-prefix", {
|
||||
</div>`
|
||||
})
|
||||
|
||||
// URL精准匹配
|
||||
Vue.component("http-cond-url-eq", {
|
||||
props: ["v-cond"],
|
||||
data: function () {
|
||||
let cond = this.vCond
|
||||
if (cond == null) {
|
||||
cond = {
|
||||
isRequest: true,
|
||||
param: "${requestPath}",
|
||||
operator: "eq",
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
return {
|
||||
cond: cond
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||
<input type="text" v-model="cond.value"/>
|
||||
</div>`
|
||||
})
|
||||
|
||||
// URL正则匹配
|
||||
Vue.component("http-cond-url-regexp", {
|
||||
props: ["v-cond"],
|
||||
data: function () {
|
||||
let cond = this.vCond
|
||||
if (cond == null) {
|
||||
cond = {
|
||||
isRequest: true,
|
||||
param: "${requestPath}",
|
||||
operator: "regexp",
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
return {
|
||||
cond: cond
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||
<input type="text" v-model="cond.value"/>
|
||||
</div>`
|
||||
})
|
||||
|
||||
// 排除URL正则匹配
|
||||
Vue.component("http-cond-url-not-regexp", {
|
||||
props: ["v-cond"],
|
||||
data: function () {
|
||||
let cond = this.vCond
|
||||
if (cond == null) {
|
||||
cond = {
|
||||
isRequest: true,
|
||||
param: "${requestPath}",
|
||||
operator: "not regexp",
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
return {
|
||||
cond: cond
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||
<input type="text" v-model="cond.value"/>
|
||||
</div>`
|
||||
})
|
||||
|
||||
// 根据MimeType
|
||||
Vue.component("http-cond-mime-type", {
|
||||
props: ["v-cond"],
|
||||
|
||||
90
web/public/js/components/server/http-fastcgi-box.js
Normal file
90
web/public/js/components/server/http-fastcgi-box.js
Normal file
@@ -0,0 +1,90 @@
|
||||
Vue.component("http-fastcgi-box", {
|
||||
props: ["v-fastcgi-ref", "v-fastcgi-configs", "v-is-location"],
|
||||
data: function () {
|
||||
let fastcgiRef = this.vFastcgiRef
|
||||
if (fastcgiRef == null) {
|
||||
fastcgiRef = {
|
||||
isPrior: false,
|
||||
isOn: false,
|
||||
fastcgiIds: []
|
||||
}
|
||||
}
|
||||
let fastcgiConfigs = this.vFastcgiConfigs
|
||||
if (fastcgiConfigs == null) {
|
||||
fastcgiConfigs = []
|
||||
} else {
|
||||
fastcgiRef.fastcgiIds = fastcgiConfigs.map(function (v) {
|
||||
return v.id
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
fastcgiRef: fastcgiRef,
|
||||
fastcgiConfigs: fastcgiConfigs,
|
||||
advancedVisible: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isOn: function () {
|
||||
return (!this.vIsLocation || this.fastcgiRef.isPrior) && this.fastcgiRef.isOn
|
||||
},
|
||||
createFastcgi: function () {
|
||||
let that = this
|
||||
teaweb.popup("/servers/server/settings/fastcgi/createPopup", {
|
||||
height: "26em",
|
||||
callback: function (resp) {
|
||||
teaweb.success("添加成功", function () {
|
||||
that.fastcgiConfigs.push(resp.data.fastcgi)
|
||||
that.fastcgiRef.fastcgiIds.push(resp.data.fastcgi.id)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
updateFastcgi: function (fastcgiId, index) {
|
||||
let that = this
|
||||
teaweb.popup("/servers/server/settings/fastcgi/updatePopup?fastcgiId=" + fastcgiId, {
|
||||
callback: function (resp) {
|
||||
teaweb.success("修改成功", function () {
|
||||
Vue.set(that.fastcgiConfigs, index, resp.data.fastcgi)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
removeFastcgi: function (index) {
|
||||
this.fastcgiRef.fastcgiIds.$remove(index)
|
||||
this.fastcgiConfigs.$remove(index)
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="fastcgiRefJSON" :value="JSON.stringify(fastcgiRef)"/>
|
||||
<table class="ui table definition selectable">
|
||||
<prior-checkbox :v-config="fastcgiRef" v-if="vIsLocation"></prior-checkbox>
|
||||
<tbody v-show="(!this.vIsLocation || this.fastcgiRef.isPrior)">
|
||||
<tr>
|
||||
<td class="title">是否启用配置</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" v-model="fastcgiRef.isOn"/>
|
||||
<label></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody v-if="isOn()">
|
||||
<tr>
|
||||
<td>Fastcgi服务</td>
|
||||
<td>
|
||||
<div v-show="fastcgiConfigs.length > 0" style="margin-bottom: 0.5em">
|
||||
<div class="ui label basic small" :class="{disabled: !fastcgi.isOn}" v-for="(fastcgi, index) in fastcgiConfigs">
|
||||
{{fastcgi.address}} <a href="" title="修改" @click.prevent="updateFastcgi(fastcgi.id, index)"><i class="ui icon pencil small"></i></a> <a href="" title="删除" @click.prevent="removeFastcgi(index)"><i class="ui icon remove"></i></a>
|
||||
</div>
|
||||
<div class="ui divided"></div>
|
||||
</div>
|
||||
<button type="button" class="ui button tiny" @click.prevent="createFastcgi()">+</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="margin"></div>
|
||||
</div>`
|
||||
})
|
||||
@@ -138,7 +138,7 @@ Vue.component("http-header-policy-box", {
|
||||
<div v-if="(!vIsLocation || requestHeaderRef.isPrior) && type == 'request'">
|
||||
<h3>设置请求Header <a href="" @click.prevent="addSettingHeader(vRequestHeaderPolicy.id)">[添加新Header]</a></h3>
|
||||
<p class="comment" v-if="requestSettingHeaders.length == 0">暂时还没有Header。</p>
|
||||
<table class="ui table selectable" v-if="requestSettingHeaders.length > 0">
|
||||
<table class="ui table selectable celled" v-if="requestSettingHeaders.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
@@ -179,8 +179,9 @@ Vue.component("http-header-policy-box", {
|
||||
|
||||
<div v-if="type == 'response'">
|
||||
<h3>设置响应Header <a href="" @click.prevent="addSettingHeader(vResponseHeaderPolicy.id)">[添加新Header]</a></h3>
|
||||
<p class="comment" style="margin-top: 0; padding-top: 0">将会覆盖已有的同名Header。</p>
|
||||
<p class="comment" v-if="responseSettingHeaders.length == 0">暂时还没有Header。</p>
|
||||
<table class="ui table selectable" v-if="responseSettingHeaders.length > 0">
|
||||
<table class="ui table selectable celled" v-if="responseSettingHeaders.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
|
||||
@@ -50,7 +50,10 @@ Vue.component("http-host-redirect-box", {
|
||||
<!-- TODO 将来支持排序,并支持isOn切换 -->
|
||||
<div v-if="redirects.length > 0">
|
||||
<div v-for="(redirect, index) in redirects" class="ui label basic small" style="margin-bottom: 0.5em;margin-top: 0.5em">
|
||||
<span v-if="redirect.status > 0">[{{redirect.status}}]</span><span v-if="redirect.matchPrefix">[prefix]</span> {{redirect.beforeURL}} -> {{redirect.afterURL}} <a href="" @click.prevent="update(index, redirect)" title="修改"><i class="icon pencil small"></i></a> <a href="" @click.prevent="remove(index)" title="删除"><i class="icon remove"></i></a>
|
||||
<span v-if="redirect.status > 0" class="small grey">[{{redirect.status}}]</span>
|
||||
<span v-if="redirect.matchPrefix" class="small grey">[匹配前缀]</span>
|
||||
<span v-if="redirect.matchRegexp" class="small grey">[正则匹配]</span>
|
||||
{{redirect.beforeURL}} -> {{redirect.afterURL}} <a href="" @click.prevent="update(index, redirect)" title="修改"><i class="icon pencil small"></i></a> <a href="" @click.prevent="remove(index)" title="删除"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
</div>
|
||||
|
||||
@@ -63,7 +63,8 @@ Vue.component("http-request-conds-box", {
|
||||
<div v-if="conds.groups.length > 0">
|
||||
<table class="ui table">
|
||||
<tr v-for="(group, groupIndex) in conds.groups">
|
||||
<td style="background: white">
|
||||
<td class="title" :style="{'border-bottom':(groupIndex < conds.groups.length-1) ? '1px solid rgba(34,36,38,.15)':''}">分组{{groupIndex+1}}</td>
|
||||
<td style="background: white;" :style="{'border-bottom':(groupIndex < conds.groups.length-1) ? '1px solid rgba(34,36,38,.15)':''}">
|
||||
<var v-for="(cond, index) in group.conds" style="font-style: normal;display: inline-block; margin-bottom:0.5em">
|
||||
<span class="ui label tiny">
|
||||
<var v-if="cond.type.length == 0" style="font-style: normal">{{cond.param}} <var>{{cond.operator}}</var></var>
|
||||
@@ -74,7 +75,7 @@ Vue.component("http-request-conds-box", {
|
||||
<var v-if="index < group.conds.length - 1"> {{group.connector}} </var>
|
||||
</var>
|
||||
</td>
|
||||
<td style="width: 5em; background: white">
|
||||
<td style="width: 5em; background: white" :style="{'border-bottom':(groupIndex < conds.groups.length-1) ? '1px solid rgba(34,36,38,.15)':''}">
|
||||
<a href="" title="修改" @click.prevent="updateGroup(groupIndex, group)"><i class="icon pencil small"></i></a> <a href="" title="删除" @click.prevent="removeGroup(groupIndex)"><i class="icon remove"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -85,6 +86,10 @@ Vue.component("http-request-conds-box", {
|
||||
<div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="addGroup()">+</button>
|
||||
</div>
|
||||
<p class="comment">
|
||||
<span v-if="conds.connector == 'or'">只要满足其中一个条件分组即可。</span>
|
||||
<span v-if="conds.connector == 'and'">需要满足所有条件分组。</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
@@ -10,10 +10,16 @@ Vue.component("http-request-conds-view", {
|
||||
}
|
||||
}
|
||||
return {
|
||||
conds: conds,
|
||||
initConds: conds,
|
||||
components: window.REQUEST_COND_COMPONENTS
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 之所以使用computed,是因为需要动态更新
|
||||
conds: function () {
|
||||
return this.initConds
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
typeName: function (cond) {
|
||||
let c = this.components.$find(function (k, v) {
|
||||
|
||||
@@ -5,7 +5,7 @@ Vue.component("http-websocket-box", {
|
||||
if (websocketRef == null) {
|
||||
websocketRef = {
|
||||
isPrior: false,
|
||||
isOn: true,
|
||||
isOn: false,
|
||||
websocketId: 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ Vue.component("origin-list-box", {
|
||||
teaweb.popup("/servers/server/settings/origins/addPopup?originType=primary&" + this.vParams, {
|
||||
height: "24em",
|
||||
callback: function (resp) {
|
||||
window.location.reload()
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -19,7 +21,9 @@ Vue.component("origin-list-box", {
|
||||
teaweb.popup("/servers/server/settings/origins/addPopup?originType=backup&" + this.vParams, {
|
||||
height: "24em",
|
||||
callback: function (resp) {
|
||||
window.location.reload()
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -27,7 +31,9 @@ Vue.component("origin-list-box", {
|
||||
teaweb.popup("/servers/server/settings/origins/updatePopup?originType=" + originType + "&" + this.vParams + "&originId=" + originId, {
|
||||
height: "24em",
|
||||
callback: function (resp) {
|
||||
window.location.reload()
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -37,7 +43,9 @@ Vue.component("origin-list-box", {
|
||||
Tea.action("/servers/server/settings/origins/delete?" + that.vParams + "&originId=" + originId + "&originType=" + originType)
|
||||
.post()
|
||||
.success(function () {
|
||||
window.location.reload()
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ Vue.component("ssl-certs-box", {
|
||||
<input type="hidden" name="certIdsJSON" :value="JSON.stringify(certIds())"/>
|
||||
<div v-if="certs != null && certs.length > 0">
|
||||
<div class="ui label small" v-for="(cert, index) in certs">
|
||||
{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}} <a href="" title="删除" @click.prevent="removeCert()"><i class="icon remove"></i></a>
|
||||
{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}} <a href="" title="删除" @click.prevent="removeCert(index)"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
<div class="ui divider" v-if="buttonsVisible()"></div>
|
||||
</div>
|
||||
|
||||
@@ -354,7 +354,7 @@ Vue.component("ssl-config-box", {
|
||||
<td>
|
||||
<div v-if="policy.certs != null && policy.certs.length > 0">
|
||||
<div class="ui label small" v-for="(cert, index) in policy.certs">
|
||||
{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}} <a href="" title="删除" @click.prevent="removeCert()"><i class="icon remove"></i></a>
|
||||
{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}} <a href="" title="删除" @click.prevent="removeCert(index)"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
</div>
|
||||
|
||||
@@ -3,18 +3,42 @@
|
||||
"type": "url-extension",
|
||||
"name": "URL扩展名",
|
||||
"description": "根据URL中的文件路径扩展名进行过滤",
|
||||
"component": "http-cond-url-extension"
|
||||
"component": "http-cond-url-extension",
|
||||
"isRequest": true
|
||||
},
|
||||
{
|
||||
"type": "url-prefix",
|
||||
"name": "路径前缀",
|
||||
"name": "URL前缀",
|
||||
"description": "根据URL中的文件路径前缀进行过滤",
|
||||
"component": "http-cond-url-prefix"
|
||||
"component": "http-cond-url-prefix",
|
||||
"isRequest": true
|
||||
},
|
||||
{
|
||||
"type": "url-eq",
|
||||
"name": "URL精准匹配",
|
||||
"description": "检查URL中的文件路径是否一致",
|
||||
"component": "http-cond-url-eq",
|
||||
"isRequest": true
|
||||
},
|
||||
{
|
||||
"type": "url-regexp",
|
||||
"name": "URL正则匹配",
|
||||
"description": "使用正则表达式检查URL中的文件路径是否一致",
|
||||
"component": "http-cond-url-regexp",
|
||||
"isRequest": true
|
||||
},
|
||||
{
|
||||
"type": "url-not-regexp",
|
||||
"name": "排除URL正则匹配",
|
||||
"description": "使用正则表达式检查URL中的文件路径是否一致,如果一致,则不匹配",
|
||||
"component": "http-cond-url-not-regexp",
|
||||
"isRequest": true
|
||||
},
|
||||
{
|
||||
"type": "mime-type",
|
||||
"name": "内容MimeType",
|
||||
"description": "根据服务器返回的内容的MimeType进行过滤",
|
||||
"component": "http-cond-mime-type"
|
||||
"description": "根据服务器返回的内容的MimeType进行过滤。注意:当用于缓存条件时,此条件需要结合别的请求条件使用。",
|
||||
"component": "http-cond-mime-type",
|
||||
"isRequest": false
|
||||
}
|
||||
]
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
<!-- 模块 -->
|
||||
<div v-for="module in teaModules">
|
||||
<a class="item" :href="Tea.url(module.code)" :class="{active:teaMenu == module.code && teaSubMenu.length == 0, separator:module.code.length == 0, expend: teaMenu == module.code}">
|
||||
<a class="item" :href="Tea.url(module.code)" :class="{active:teaMenu == module.code && teaSubMenu.length == 0, separator:module.code.length == 0, expend: teaMenu == module.code}" v-if="module.isOn !== false">
|
||||
<span v-if="module.code.length > 0">
|
||||
<i class="window restore outline icon" v-if="module.icon == null"></i>
|
||||
<i class="ui icon" v-if="module.icon != null" :class="module.icon"></i>
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
<menu-item :href="'/clusters/cluster?clusterId=' + clusterId">节点列表</menu-item>
|
||||
<span class="item">|</span>
|
||||
<menu-item :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + nodeId" code="node">节点详情</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/logs?clusterId=' + clusterId + '&nodeId=' + nodeId" code="log">运行日志</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/monitor?clusterId=' + clusterId + '&nodeId=' + nodeId" code="monitor" v-if="teaIsPlus">监控图表</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/thresholds?clusterId=' + clusterId + '&nodeId=' + nodeId" code="threshold" v-if="teaIsPlus">阈值设置</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/logs?clusterId=' + clusterId + '&nodeId=' + nodeId" code="log">运行日志</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/update?clusterId=' + clusterId + '&nodeId=' + nodeId" code="update">修改设置</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + nodeId" code="install">安装节点</menu-item>
|
||||
</second-menu>
|
||||
@@ -1,20 +1,58 @@
|
||||
{$layout}
|
||||
{$template "node_menu"}
|
||||
|
||||
{$template "node_menu"}
|
||||
{$var "header"}
|
||||
<!-- datepicker -->
|
||||
<script type="text/javascript" src="/js/moment.min.js"></script>
|
||||
<script type="text/javascript" src="/js/pikaday.js"></script>
|
||||
<link rel="stylesheet" href="/js/pikaday.css"/>
|
||||
<link rel="stylesheet" href="/js/pikaday.theme.css"/>
|
||||
<link rel="stylesheet" href="/js/pikaday.triangle.css"/>
|
||||
{$end}
|
||||
|
||||
<p class="comment" v-if="logs.length == 0">暂时还没有日志。</p>
|
||||
<form method="get" action="/clusters/cluster/node/logs" class="ui form" autocomplete="off">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<input type="hidden" name="nodeId" :value="nodeId"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="dayFrom" placeholder="开始日期" v-model="dayFrom" value="" style="width:8em" id="day-from-picker"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="dayTo" placeholder="结束日期" v-model="dayTo" value="" style="width:8em" id="day-to-picker"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" name="level" v-model="level">
|
||||
<option value="">[级别]</option>
|
||||
<option value="error">错误</option>
|
||||
<option value="warning">警告</option>
|
||||
<option value="info">信息</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" style="width:10em" v-model="keyword" placeholder="关键词"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button type="submit" class="ui button">查询</button>
|
||||
</div>
|
||||
<div class="ui field" v-if="dayFrom.length > 0 || dayTo.length > 0 || keyword.length > 0 || level.length > 0">
|
||||
<a :href="'/clusters/cluster/node/logs?clusterId=' + clusterId + '&nodeId=' + nodeId">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<table class="ui table selectable" v-if="logs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<p class="comment" v-if="logs.length == 0">暂时还没有日志。</p>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="log in logs">
|
||||
<td>
|
||||
<pre class="log-box"><span :class="{red:log.level == 'error', yellow:log.level == 'warning'}"><span v-if="!log.isToday">[{{log.createdTime}}]</span><strong v-if="log.isToday">[{{log.createdTime}}]</strong>[{{log.tag}}]{{log.description}}</span></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="ui table selectable" v-if="logs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="log in logs">
|
||||
<td>
|
||||
<pre class="log-box"><span :class="{red:log.level == 'error', yellow:log.level == 'warning'}"><span v-if="!log.isToday">[{{log.createdTime}}]</span><strong v-if="log.isToday">[{{log.createdTime}}]</strong>[{{log.tag}}]{{log.description}}</span> <span v-if="log.count > 0" class="ui label tiny red">共{{log.count}}条</span></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
6
web/views/@default/clusters/cluster/node/logs.js
Normal file
6
web/views/@default/clusters/cluster/node/logs.js
Normal file
@@ -0,0 +1,6 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
teaweb.datepicker("day-from-picker")
|
||||
teaweb.datepicker("day-to-picker")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,4 @@
|
||||
.chart-box {
|
||||
height: 20em;
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,YAAA","file":"index.css"}
|
||||
25
web/views/@default/clusters/cluster/node/monitor/index.html
Normal file
25
web/views/@default/clusters/cluster/node/monitor/index.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{$layout}
|
||||
{$template "../node_menu"}
|
||||
|
||||
{$var "header"}
|
||||
<!-- echart -->
|
||||
<script type="text/javascript" src="/js/echarts/echarts.min.js"></script>
|
||||
{$end}
|
||||
|
||||
<h4>上行流量(字节)</h4>
|
||||
<div class="chart-box" id="traffic-in-chart"></div>
|
||||
|
||||
<h4>下行流量(字节)</h4>
|
||||
<div class="chart-box" id="traffic-out-chart"></div>
|
||||
|
||||
<h4>连接数</h4>
|
||||
<div class="chart-box" id="connections-chart"></div>
|
||||
|
||||
<h4>CPU</h4>
|
||||
<div class="chart-box" id="cpu-chart"></div>
|
||||
|
||||
<h4>内存</h4>
|
||||
<div class="chart-box" id="memory-chart"></div>
|
||||
|
||||
<h4>负载</h4>
|
||||
<div class="chart-box" id="load-chart"></div>
|
||||
253
web/views/@default/clusters/cluster/node/monitor/index.js
Normal file
253
web/views/@default/clusters/cluster/node/monitor/index.js
Normal file
@@ -0,0 +1,253 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
this.loadTrafficInChart()
|
||||
this.loadTrafficOutChart()
|
||||
this.loadConnectionsChart()
|
||||
this.loadCPUChart()
|
||||
this.loadMemoryChart()
|
||||
this.loadLoadChart()
|
||||
|
||||
let that = this
|
||||
window.addEventListener("resize", function () {
|
||||
that.resizeChart("traffic-in-chart")
|
||||
that.resizeChart("traffic-out-chart")
|
||||
that.resizeChart("connections-chart")
|
||||
that.resizeChart("cpu-chart")
|
||||
that.resizeChart("memory-chart")
|
||||
that.resizeChart("load-chart")
|
||||
})
|
||||
})
|
||||
|
||||
this.loadTrafficInChart = function () {
|
||||
this.$post(".trafficIn")
|
||||
.params({
|
||||
nodeId: this.nodeId
|
||||
})
|
||||
.success(function (resp) {
|
||||
let values = resp.data.values
|
||||
let maxFunc = function () {
|
||||
let max = values.map(function (v) {
|
||||
return v.value
|
||||
}).$max() / 1024 / 1024
|
||||
if (max < 1) {
|
||||
return 1
|
||||
}
|
||||
if (max < 10) {
|
||||
return 10
|
||||
}
|
||||
if (max < 100) {
|
||||
return 100
|
||||
}
|
||||
return null
|
||||
}
|
||||
let valueFunc = function (v) {
|
||||
return v.value / 1024 / 1024
|
||||
}
|
||||
this.reloadChart("traffic-in-chart", "", values, "M", maxFunc, valueFunc)
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
this.loadTrafficInChart()
|
||||
}, 30000)
|
||||
})
|
||||
}
|
||||
|
||||
this.loadTrafficOutChart = function () {
|
||||
this.$post(".trafficOut")
|
||||
.params({
|
||||
nodeId: this.nodeId
|
||||
})
|
||||
.success(function (resp) {
|
||||
let values = resp.data.values
|
||||
let maxFunc = function () {
|
||||
let max = values.map(function (v) {
|
||||
return v.value
|
||||
}).$max() / 1024 / 1024
|
||||
if (max < 1) {
|
||||
return 1
|
||||
}
|
||||
if (max < 10) {
|
||||
return 10
|
||||
}
|
||||
if (max < 100) {
|
||||
return 100
|
||||
}
|
||||
return null
|
||||
}
|
||||
let valueFunc = function (v) {
|
||||
return v.value / 1024 / 1024
|
||||
}
|
||||
this.reloadChart("traffic-out-chart", "", values, "M", maxFunc, valueFunc)
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
this.loadTrafficOutChart()
|
||||
}, 30000)
|
||||
})
|
||||
}
|
||||
|
||||
this.loadConnectionsChart = function () {
|
||||
this.$post(".connections")
|
||||
.params({
|
||||
nodeId: this.nodeId
|
||||
})
|
||||
.success(function (resp) {
|
||||
let values = resp.data.values
|
||||
let maxFunc = function () {
|
||||
let max = values.map(function (v) {
|
||||
return v.value
|
||||
}).$max()
|
||||
if (max < 10) {
|
||||
return 10
|
||||
}
|
||||
if (max < 100) {
|
||||
return 100
|
||||
}
|
||||
if (max < 1000) {
|
||||
return 1000
|
||||
}
|
||||
return null
|
||||
}
|
||||
let valueFunc = function (v) {
|
||||
return v.value
|
||||
}
|
||||
this.reloadChart("connections-chart", "", values, "", maxFunc, valueFunc)
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
this.loadConnectionsChart()
|
||||
}, 30000)
|
||||
})
|
||||
}
|
||||
|
||||
this.loadCPUChart = function () {
|
||||
this.$post(".cpu")
|
||||
.params({
|
||||
nodeId: this.nodeId
|
||||
})
|
||||
.success(function (resp) {
|
||||
let values = resp.data.values
|
||||
let maxFunc = function () {
|
||||
return 100
|
||||
}
|
||||
let valueFunc = function (v) {
|
||||
return v.value
|
||||
}
|
||||
this.reloadChart("cpu-chart", "", values, "%", maxFunc, valueFunc)
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
this.loadCPUChart()
|
||||
}, 30000)
|
||||
})
|
||||
}
|
||||
|
||||
this.loadMemoryChart = function () {
|
||||
this.$post(".memory")
|
||||
.params({
|
||||
nodeId: this.nodeId
|
||||
})
|
||||
.success(function (resp) {
|
||||
let values = resp.data.values
|
||||
let maxFunc = function () {
|
||||
return 100
|
||||
}
|
||||
let valueFunc = function (v) {
|
||||
return v.value
|
||||
}
|
||||
this.reloadChart("memory-chart", "", values, "%", maxFunc, valueFunc)
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
this.loadMemoryChart()
|
||||
}, 30000)
|
||||
})
|
||||
}
|
||||
|
||||
this.loadLoadChart = function () {
|
||||
this.$post(".load")
|
||||
.params({
|
||||
nodeId: this.nodeId
|
||||
})
|
||||
.success(function (resp) {
|
||||
let values = resp.data.values
|
||||
let maxFunc = function () {
|
||||
let max = values.map(function (v) {
|
||||
return v.value
|
||||
}).$max()
|
||||
if (max < 10) {
|
||||
return 10
|
||||
}
|
||||
return null
|
||||
}
|
||||
let valueFunc = function (v) {
|
||||
return v.value
|
||||
}
|
||||
this.reloadChart("load-chart", "5分钟", values, "", maxFunc, valueFunc)
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
this.loadLoadChart()
|
||||
}, 30000)
|
||||
})
|
||||
}
|
||||
|
||||
this.reloadChart = function (chartId, name, stats, unit, maxFunc, valueFunc) {
|
||||
let chartBox = document.getElementById(chartId)
|
||||
if (chartBox == null) {
|
||||
return
|
||||
}
|
||||
let chart = echarts.init(chartBox)
|
||||
let option = {
|
||||
xAxis: {
|
||||
data: stats.map(function (stat) {
|
||||
return stat.label
|
||||
})
|
||||
},
|
||||
yAxis: {
|
||||
max: maxFunc(),
|
||||
axisLabel: {
|
||||
formatter: function (value) {
|
||||
return value + unit
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
trigger: "item",
|
||||
formatter: function (args) {
|
||||
return stats[args.dataIndex].label + ": " + stats[args.dataIndex].text
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: 50,
|
||||
top: 10,
|
||||
right: 20,
|
||||
bottom: 20
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: name,
|
||||
type: "line",
|
||||
data: stats.map(valueFunc),
|
||||
itemStyle: {
|
||||
color: "#9DD3E8"
|
||||
},
|
||||
areaStyle: {}
|
||||
}
|
||||
],
|
||||
animation: true
|
||||
}
|
||||
chart.setOption(option)
|
||||
chart.resize()
|
||||
}
|
||||
|
||||
this.resizeChart = function (chartId) {
|
||||
let chartBox = document.getElementById(chartId)
|
||||
if (chartBox == null) {
|
||||
return
|
||||
}
|
||||
let chart = echarts.init(chartBox)
|
||||
chart.resize()
|
||||
}
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user