Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f738ba9152 | ||
|
|
95c27119ac | ||
|
|
2b2b516788 | ||
|
|
0bb63b5bb7 | ||
|
|
48012072d7 | ||
|
|
0053949bc0 | ||
|
|
88e7246366 | ||
|
|
fbedf3b605 | ||
|
|
d5659e627d | ||
|
|
709d4dc805 | ||
|
|
37f052e9a5 | ||
|
|
58c765e97f | ||
|
|
da332c2756 | ||
|
|
e9d329bf8b |
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
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "0.1.0"
|
Version = "0.1.1"
|
||||||
|
|
||||||
ProductName = "Edge Admin"
|
ProductName = "Edge Admin"
|
||||||
ProcessName = "edge-admin"
|
ProcessName = "edge-admin"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RPC客户端
|
// RPCClient RPC客户端
|
||||||
type RPCClient struct {
|
type RPCClient struct {
|
||||||
apiConfig *configs.APIConfig
|
apiConfig *configs.APIConfig
|
||||||
conns []*grpc.ClientConn
|
conns []*grpc.ClientConn
|
||||||
@@ -30,7 +30,7 @@ type RPCClient struct {
|
|||||||
locker sync.Mutex
|
locker sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构造新的RPC客户端
|
// NewRPCClient 构造新的RPC客户端
|
||||||
func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
|
func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
|
||||||
if apiConfig == nil {
|
if apiConfig == nil {
|
||||||
return nil, errors.New("api config should not be nil")
|
return nil, errors.New("api config should not be nil")
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func TestRPC_Dial_HTTP(t *testing.T) {
|
|||||||
RPC: struct {
|
RPC: struct {
|
||||||
Endpoints []string `yaml:"endpoints"`
|
Endpoints []string `yaml:"endpoints"`
|
||||||
}{
|
}{
|
||||||
Endpoints: []string{"127.0.0.1:8003"},
|
Endpoints: []string{"http://127.0.0.1:8004"},
|
||||||
},
|
},
|
||||||
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||||
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||||
@@ -58,7 +58,7 @@ func TestRPC_Dial_HTTP_2(t *testing.T) {
|
|||||||
RPC: struct {
|
RPC: struct {
|
||||||
Endpoints []string `yaml:"endpoints"`
|
Endpoints []string `yaml:"endpoints"`
|
||||||
}{
|
}{
|
||||||
Endpoints: []string{"http://127.0.0.1:8003"},
|
Endpoints: []string{"https://127.0.0.1:8003"},
|
||||||
},
|
},
|
||||||
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||||
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||||
|
|||||||
@@ -17,13 +17,25 @@ func (this *LogsAction) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *LogsAction) RunGet(params struct {
|
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["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{
|
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||||
Role: "node",
|
Role: "node",
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
|
DayFrom: params.DayFrom,
|
||||||
|
DayTo: params.DayTo,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Level: params.Level,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
@@ -33,10 +45,14 @@ func (this *LogsAction) RunGet(params struct {
|
|||||||
page := this.NewPage(count, 20)
|
page := this.NewPage(count, 20)
|
||||||
|
|
||||||
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
|
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
Role: "node",
|
Role: "node",
|
||||||
Offset: page.Offset,
|
DayFrom: params.DayFrom,
|
||||||
Size: page.Size,
|
DayTo: params.DayTo,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Level: params.Level,
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
})
|
})
|
||||||
|
|
||||||
logs := []maps.Map{}
|
logs := []maps.Map{}
|
||||||
@@ -47,6 +63,7 @@ func (this *LogsAction) RunGet(params struct {
|
|||||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
|
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
|
||||||
"level": log.Level,
|
"level": log.Level,
|
||||||
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
|
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
|
||||||
|
"count": log.Count,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.Data["logs"] = logs
|
this.Data["logs"] = logs
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ func (this *TrafficInAction) RunPost(params struct {
|
|||||||
if ok {
|
if ok {
|
||||||
result = append(result, maps.Map{
|
result = append(result, maps.Map{
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
"label": timeutil.FormatTime("H:i", timestamp),
|
||||||
"value": total,
|
"value": total / 60,
|
||||||
"text": numberutils.FormatBytes(total),
|
"text": numberutils.FormatBytes(total / 60),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
result = append(result, maps.Map{
|
result = append(result, maps.Map{
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ func (this *TrafficOutAction) RunPost(params struct {
|
|||||||
if ok {
|
if ok {
|
||||||
result = append(result, maps.Map{
|
result = append(result, maps.Map{
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
"label": timeutil.FormatTime("H:i", timestamp),
|
||||||
"value": total,
|
"value": total / 60,
|
||||||
"text": numberutils.FormatBytes(total),
|
"text": numberutils.FormatBytes(total / 60),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
result = append(result, maps.Map{
|
result = append(result, maps.Map{
|
||||||
|
|||||||
@@ -15,8 +15,14 @@ func (this *IndexAction) Init() {
|
|||||||
this.Nav("", "grant", "index")
|
this.Nav("", "grant", "index")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct{}) {
|
func (this *IndexAction) RunGet(params struct {
|
||||||
countResp, err := this.RPC().NodeGrantRPC().CountAllEnabledNodeGrants(this.AdminContext(), &pb.CountAllEnabledNodeGrantsRequest{})
|
Keyword string
|
||||||
|
}) {
|
||||||
|
this.Data["keyword"] = params.Keyword
|
||||||
|
|
||||||
|
countResp, err := this.RPC().NodeGrantRPC().CountAllEnabledNodeGrants(this.AdminContext(), &pb.CountAllEnabledNodeGrantsRequest{
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -25,8 +31,9 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
this.Data["page"] = page.AsHTML()
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
grantsResp, err := this.RPC().NodeGrantRPC().ListEnabledNodeGrants(this.AdminContext(), &pb.ListEnabledNodeGrantsRequest{
|
grantsResp, err := this.RPC().NodeGrantRPC().ListEnabledNodeGrants(this.AdminContext(), &pb.ListEnabledNodeGrantsRequest{
|
||||||
Offset: page.Offset,
|
Keyword: params.Keyword,
|
||||||
Size: page.Size,
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
@@ -57,6 +64,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
"type": grant.Method,
|
"type": grant.Method,
|
||||||
"name": grantutils.FindGrantMethodName(grant.Method),
|
"name": grantutils.FindGrantMethodName(grant.Method),
|
||||||
},
|
},
|
||||||
|
"username": grant.Username,
|
||||||
"countClusters": countClusters,
|
"countClusters": countClusters,
|
||||||
"countNodes": countNodes,
|
"countNodes": countNodes,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,10 +27,12 @@ func (this *SelectPopupAction) RunGet(params struct{}) {
|
|||||||
grantMaps := []maps.Map{}
|
grantMaps := []maps.Map{}
|
||||||
for _, grant := range grants {
|
for _, grant := range grants {
|
||||||
grantMaps = append(grantMaps, maps.Map{
|
grantMaps = append(grantMaps, maps.Map{
|
||||||
"id": grant.Id,
|
"id": grant.Id,
|
||||||
"name": grant.Name,
|
"name": grant.Name,
|
||||||
"method": grant.Method,
|
"method": grant.Method,
|
||||||
"methodName": grantutils.FindGrantMethodName(grant.Method),
|
"methodName": grantutils.FindGrantMethodName(grant.Method),
|
||||||
|
"username": grant.Username,
|
||||||
|
"description": grant.Description,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.Data["grants"] = grantMaps
|
this.Data["grants"] = grantMaps
|
||||||
|
|||||||
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()
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -6,10 +6,12 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MessageResult 和节点消息通讯结果定义
|
||||||
type MessageResult struct {
|
type MessageResult struct {
|
||||||
NodeId int64 `json:"nodeId"`
|
NodeId int64 `json:"nodeId"`
|
||||||
NodeName string `json:"nodeName"`
|
NodeName string `json:"nodeName"`
|
||||||
@@ -17,7 +19,7 @@ type MessageResult struct {
|
|||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向集群发送命令消息
|
// SendMessageToCluster 向集群发送命令消息
|
||||||
func SendMessageToCluster(ctx context.Context, clusterId int64, code string, msg interface{}, timeoutSeconds int32) (results []*MessageResult, err error) {
|
func SendMessageToCluster(ctx context.Context, clusterId int64, code string, msg interface{}, timeoutSeconds int32) (results []*MessageResult, err error) {
|
||||||
results = []*MessageResult{}
|
results = []*MessageResult{}
|
||||||
|
|
||||||
@@ -153,10 +155,17 @@ func SendMessageToCluster(ctx context.Context, clusterId int64, code string, msg
|
|||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
|
// 对结果进行排序
|
||||||
|
if len(results) > 0 {
|
||||||
|
sort.Slice(results, func(i, j int) bool {
|
||||||
|
return results[i].NodeId < results[j].NodeId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向一组节点发送命令消息
|
// SendMessageToNodeIds 向一组节点发送命令消息
|
||||||
func SendMessageToNodeIds(ctx context.Context, nodeIds []int64, code string, msg interface{}, timeoutSeconds int32) (results []*MessageResult, err error) {
|
func SendMessageToNodeIds(ctx context.Context, nodeIds []int64, code string, msg interface{}, timeoutSeconds int32) (results []*MessageResult, err error) {
|
||||||
results = []*MessageResult{}
|
results = []*MessageResult{}
|
||||||
if len(nodeIds) == 0 {
|
if len(nodeIds) == 0 {
|
||||||
@@ -321,5 +330,12 @@ func SendMessageToNodeIds(ctx context.Context, nodeIds []int64, code string, msg
|
|||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
|
// 对结果进行排序
|
||||||
|
if len(results) > 0 {
|
||||||
|
sort.Slice(results, func(i, j int) bool {
|
||||||
|
return results[i].NodeId < results[j].NodeId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 选择证书
|
// SelectPopupAction 选择证书
|
||||||
type SelectPopupAction struct {
|
type SelectPopupAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
}
|
}
|
||||||
@@ -25,10 +25,12 @@ func (this *SelectPopupAction) Init() {
|
|||||||
func (this *SelectPopupAction) RunGet(params struct {
|
func (this *SelectPopupAction) RunGet(params struct {
|
||||||
ViewSize string
|
ViewSize string
|
||||||
SelectedCertIds string
|
SelectedCertIds string
|
||||||
|
Keyword string
|
||||||
}) {
|
}) {
|
||||||
// TODO 支持关键词搜索
|
|
||||||
// TODO 列出常用和最新的证书供用户选择
|
// TODO 列出常用和最新的证书供用户选择
|
||||||
|
|
||||||
|
this.Data["keyword"] = params.Keyword
|
||||||
|
|
||||||
// 已经选择的证书
|
// 已经选择的证书
|
||||||
selectedCertIds := []string{}
|
selectedCertIds := []string{}
|
||||||
if len(params.SelectedCertIds) > 0 {
|
if len(params.SelectedCertIds) > 0 {
|
||||||
@@ -40,7 +42,9 @@ func (this *SelectPopupAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
this.Data["viewSize"] = params.ViewSize
|
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 {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -50,8 +54,9 @@ func (this *SelectPopupAction) RunGet(params struct {
|
|||||||
this.Data["page"] = page.AsHTML()
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
listResp, err := this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
listResp, err := this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||||
Offset: page.Offset,
|
Keyword: params.Keyword,
|
||||||
Size: page.Size,
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
})
|
})
|
||||||
|
|
||||||
certConfigs := []*sslconfigs.SSLCertConfig{}
|
certConfigs := []*sslconfigs.SSLCertConfig{}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
strings "strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PurgeAction struct {
|
type PurgeAction struct {
|
||||||
@@ -53,6 +53,7 @@ func (this *PurgeAction) RunGet(params struct {
|
|||||||
func (this *PurgeAction) RunPost(params struct {
|
func (this *PurgeAction) RunPost(params struct {
|
||||||
CachePolicyId int64
|
CachePolicyId int64
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
|
Type string
|
||||||
Keys string
|
Keys string
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
@@ -96,6 +97,11 @@ func (this *PurgeAction) RunPost(params struct {
|
|||||||
CachePolicyJSON: cachePolicyJSON,
|
CachePolicyJSON: cachePolicyJSON,
|
||||||
Keys: realKeys,
|
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)
|
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodePurgeCache, msg, 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -63,8 +63,13 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
Description string
|
Description string
|
||||||
IsOn bool
|
IsOn bool
|
||||||
|
|
||||||
|
RefsJSON []byte
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
|
// 创建日志
|
||||||
|
defer this.CreateLog(oplogs.LevelInfo, "修改缓存策略:%d", params.CachePolicyId)
|
||||||
|
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("name", params.Name).
|
Field("name", params.Name).
|
||||||
Require("请输入策略名称")
|
Require("请输入策略名称")
|
||||||
@@ -104,6 +109,22 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
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{
|
_, err = this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicy(this.AdminContext(), &pb.UpdateHTTPCachePolicyRequest{
|
||||||
HttpCachePolicyId: params.CachePolicyId,
|
HttpCachePolicyId: params.CachePolicyId,
|
||||||
IsOn: params.IsOn,
|
IsOn: params.IsOn,
|
||||||
@@ -120,8 +141,15 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
return
|
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()
|
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"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"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/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -250,5 +252,48 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
// 是否有用户管理权限
|
// 是否有用户管理权限
|
||||||
this.Data["canVisitUser"] = configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeUser)
|
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()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ func init() {
|
|||||||
Get("", new(IndexAction)).
|
Get("", new(IndexAction)).
|
||||||
GetPost("/create", new(CreateAction)).
|
GetPost("/create", new(CreateAction)).
|
||||||
GetPost("/update", new(UpdateAction)).
|
GetPost("/update", new(UpdateAction)).
|
||||||
|
Post("/fixLog", new(FixLogAction)).
|
||||||
|
|
||||||
GetPost("/addPortPopup", new(AddPortPopupAction)).
|
GetPost("/addPortPopup", new(AddPortPopupAction)).
|
||||||
GetPost("/addServerNamePopup", new(AddServerNamePopupAction)).
|
GetPost("/addServerNamePopup", new(AddServerNamePopupAction)).
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -76,6 +78,24 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
this.Fail("端口地址解析失败:" + err.Error())
|
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)
|
server, _, isOk := serverutils.FindServer(this.Parent(), params.ServerId)
|
||||||
if !isOk {
|
if !isOk {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -87,7 +88,23 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
this.Fail("端口地址解析失败:" + err.Error())
|
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
|
// 校验SSL
|
||||||
var sslPolicyId = int64(0)
|
var sslPolicyId = int64(0)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreatePopupAction struct {
|
type CreatePopupAction struct {
|
||||||
@@ -27,6 +28,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
BeforeURL string
|
BeforeURL string
|
||||||
AfterURL string
|
AfterURL string
|
||||||
MatchPrefix bool
|
MatchPrefix bool
|
||||||
|
MatchRegexp bool
|
||||||
KeepRequestURI bool
|
KeepRequestURI bool
|
||||||
|
|
||||||
Status int
|
Status int
|
||||||
@@ -39,7 +41,12 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
Require("请填写跳转前的URL")
|
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)
|
u, err := url.Parse(params.BeforeURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.FailField("beforeURL", "请输入正确的跳转前URL")
|
this.FailField("beforeURL", "请输入正确的跳转前URL")
|
||||||
@@ -56,7 +63,9 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
Require("请填写跳转后URL")
|
Require("请填写跳转后URL")
|
||||||
|
|
||||||
// 校验格式
|
// 校验格式
|
||||||
{
|
if params.MatchRegexp {
|
||||||
|
// 正则表达式情况下不做校验
|
||||||
|
} else {
|
||||||
u, err := url.Parse(params.AfterURL)
|
u, err := url.Parse(params.AfterURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.FailField("afterURL", "请输入正确的跳转后URL")
|
this.FailField("afterURL", "请输入正确的跳转后URL")
|
||||||
@@ -76,6 +85,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
"beforeURL": params.BeforeURL,
|
"beforeURL": params.BeforeURL,
|
||||||
"afterURL": params.AfterURL,
|
"afterURL": params.AfterURL,
|
||||||
"matchPrefix": params.MatchPrefix,
|
"matchPrefix": params.MatchPrefix,
|
||||||
|
"matchRegexp": params.MatchRegexp,
|
||||||
"keepRequestURI": params.KeepRequestURI,
|
"keepRequestURI": params.KeepRequestURI,
|
||||||
"isOn": true,
|
"isOn": true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,6 +181,11 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
|||||||
"subtitle": "集群列表",
|
"subtitle": "集群列表",
|
||||||
"icon": "cloud",
|
"icon": "cloud",
|
||||||
"subItems": []maps.Map{
|
"subItems": []maps.Map{
|
||||||
|
{
|
||||||
|
"name": "节点日志",
|
||||||
|
"url": "/clusters/logs",
|
||||||
|
"code": "log",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "SSH认证",
|
"name": "SSH认证",
|
||||||
"url": "/clusters/grants",
|
"url": "/clusters/grants",
|
||||||
|
|||||||
@@ -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"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings"
|
_ "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/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"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/regions/items"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/regions/items"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/tasks"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/tasks"
|
||||||
|
|||||||
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>`
|
||||||
|
})
|
||||||
@@ -50,7 +50,10 @@ Vue.component("http-host-redirect-box", {
|
|||||||
<!-- TODO 将来支持排序,并支持isOn切换 -->
|
<!-- TODO 将来支持排序,并支持isOn切换 -->
|
||||||
<div v-if="redirects.length > 0">
|
<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">
|
<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>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ Vue.component("origin-list-box", {
|
|||||||
teaweb.popup("/servers/server/settings/origins/addPopup?originType=primary&" + this.vParams, {
|
teaweb.popup("/servers/server/settings/origins/addPopup?originType=primary&" + this.vParams, {
|
||||||
height: "24em",
|
height: "24em",
|
||||||
callback: function (resp) {
|
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, {
|
teaweb.popup("/servers/server/settings/origins/addPopup?originType=backup&" + this.vParams, {
|
||||||
height: "24em",
|
height: "24em",
|
||||||
callback: function (resp) {
|
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, {
|
teaweb.popup("/servers/server/settings/origins/updatePopup?originType=" + originType + "&" + this.vParams + "&originId=" + originId, {
|
||||||
height: "24em",
|
height: "24em",
|
||||||
callback: function (resp) {
|
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)
|
Tea.action("/servers/server/settings/origins/delete?" + that.vParams + "&originId=" + originId + "&originType=" + originType)
|
||||||
.post()
|
.post()
|
||||||
.success(function () {
|
.success(function () {
|
||||||
window.location.reload()
|
teaweb.success("保存成功", function () {
|
||||||
|
window.location.reload()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,58 @@
|
|||||||
{$layout}
|
{$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">
|
<p class="comment" v-if="logs.length == 0">暂时还没有日志。</p>
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
</tr>
|
<table class="ui table selectable" v-if="logs.length > 0">
|
||||||
</thead>
|
<thead>
|
||||||
<tr v-for="log in logs">
|
<tr>
|
||||||
<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>
|
|
||||||
|
|
||||||
<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")
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,6 +1,21 @@
|
|||||||
{$layout}
|
{$layout}
|
||||||
{$template "menu"}
|
{$template "menu"}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 搜索表单 -->
|
||||||
|
<form class="ui form" method="get" action="/clusters/grants">
|
||||||
|
<div class="margin"></div>
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<input type="text" name="keyword" placeholder="名称、用户名等..." v-model="keyword"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<button class="ui button" type="submit">搜索</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- SSH认证列表 -->
|
||||||
<div class="ui message" v-if="grants.length == 0">暂时还没有认证信息。</div>
|
<div class="ui message" v-if="grants.length == 0">暂时还没有认证信息。</div>
|
||||||
|
|
||||||
<table class="ui table selectable celled" v-if="grants.length > 0">
|
<table class="ui table selectable celled" v-if="grants.length > 0">
|
||||||
@@ -8,6 +23,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>名称</th>
|
<th>名称</th>
|
||||||
<th>类型</th>
|
<th>类型</th>
|
||||||
|
<th>用户名</th>
|
||||||
<th class="center width5">集群数</th>
|
<th class="center width5">集群数</th>
|
||||||
<th class="center width5">节点数</th>
|
<th class="center width5">节点数</th>
|
||||||
<th class="two op">操作</th>
|
<th class="two op">操作</th>
|
||||||
@@ -18,6 +34,10 @@
|
|||||||
<td>
|
<td>
|
||||||
<span class="ui label tiny basic">{{grant.method.name}}</span>
|
<span class="ui label tiny basic">{{grant.method.name}}</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="grant.username.length > 0">{{grant.username}}</span>
|
||||||
|
<span v-else class="disabled">-</span>
|
||||||
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<span v-if="grant.countClusters > 0">{{grant.countClusters}}</span>
|
<span v-if="grant.countClusters > 0">{{grant.countClusters}}</span>
|
||||||
<span v-else class="disabled">0</span>
|
<span v-else class="disabled">0</span>
|
||||||
|
|||||||
@@ -2,11 +2,19 @@
|
|||||||
|
|
||||||
<h3>选择认证</h3>
|
<h3>选择认证</h3>
|
||||||
|
|
||||||
<table class="ui table definition">
|
<form class="ui form">
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<input type="text" placeholder="搜索名称、用户名等" v-model="keyword"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<table class="ui table">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<span v-if="grants.length == 0">暂时还没有可用的认证。</span>
|
<span v-if="grants.length == 0">暂时还没有可用的认证。</span>
|
||||||
<a class="ui label small basic" v-for="grant in grants" :class="{blue:grantId == grant.id}" @click.prevent="selectGrant(grant)" style="margin-bottom:0.5em">{{grant.name}} <span class="small">({{grant.methodName}})</span></a>
|
<a class="ui label small basic" v-for="grant in grants" :class="{blue:grantId == grant.id}" @click.prevent="selectGrant(grant)" style="margin-bottom:0.5em">{{grant.name}} <span class="small">({{grant.methodName}})</span><span v-if="grant.username.length > 0" class="small">({{grant.username}})</span></a>
|
||||||
<p class="comment">请点击选中某个认证。</p>
|
<p class="comment">请点击选中某个认证。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.grantId = 0;
|
this.grantId = 0
|
||||||
|
this.keyword = ""
|
||||||
|
let allGrants = this.grants.$copy()
|
||||||
|
|
||||||
this.selectGrant = function (grant) {
|
this.selectGrant = function (grant) {
|
||||||
NotifyPopup({
|
NotifyPopup({
|
||||||
@@ -8,5 +10,20 @@ Tea.context(function () {
|
|||||||
grant: grant
|
grant: grant
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
this.$delay(function () {
|
||||||
|
let that = this
|
||||||
|
this.$watch("keyword", function (keyword) {
|
||||||
|
if (keyword.length > 0) {
|
||||||
|
that.grants = allGrants.$findAll(function (k, grant) {
|
||||||
|
return teaweb.match(grant.name, keyword)
|
||||||
|
|| teaweb.match(grant.description, keyword)
|
||||||
|
|| teaweb.match(grant.username, keyword)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
that.grants = allGrants
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
5
web/views/@default/clusters/logs/index.css
Normal file
5
web/views/@default/clusters/logs/index.css
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pre.log-box {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=index.css.map */
|
||||||
1
web/views/@default/clusters/logs/index.css.map
Normal file
1
web/views/@default/clusters/logs/index.css.map
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,GAAG;EACF,SAAA;EACA,UAAA","file":"index.css"}
|
||||||
62
web/views/@default/clusters/logs/index.html
Normal file
62
web/views/@default/clusters/logs/index.html
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{$layout}
|
||||||
|
|
||||||
|
{$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}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="margin"></div>
|
||||||
|
|
||||||
|
<form method="get" action="/clusters/logs" class="ui form" autocomplete="off">
|
||||||
|
<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/logs">[清除条件]</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="comment" v-if="logs.length == 0">暂时还没有日志。</p>
|
||||||
|
|
||||||
|
<table class="ui table selectable celled" v-if="logs.length > 0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>集群</th>
|
||||||
|
<th>节点</th>
|
||||||
|
<th>信息</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="log in logs">
|
||||||
|
<td nowrap=""><link-icon :href="'/clusters/cluster?clusterId=' + log.node.cluster.id">{{log.node.cluster.name}}</link-icon></td>
|
||||||
|
<td nowrap=""><link-icon :href="'/clusters/cluster/node?clusterId=' + log.node.cluster.id + '&nodeId=' + log.node.id">{{log.node.name}}</link-icon></td>
|
||||||
|
<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/logs/index.js
Normal file
6
web/views/@default/clusters/logs/index.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.$delay(function () {
|
||||||
|
teaweb.datepicker("day-from-picker")
|
||||||
|
teaweb.datepicker("day-to-picker")
|
||||||
|
})
|
||||||
|
})
|
||||||
4
web/views/@default/clusters/logs/index.less
Normal file
4
web/views/@default/clusters/logs/index.less
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pre.log-box {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
@@ -1,6 +1,20 @@
|
|||||||
{$layout "layout_popup"}
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
<h3>选择证书</h3>
|
<h3>选择证书</h3>
|
||||||
|
|
||||||
|
<!-- 搜索表单 -->
|
||||||
|
<form class="ui form" action="/servers/certs/selectPopup">
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<input type="text" name="keyword" v-model="keyword" placeholder="域名、说明文字等"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<button class="ui button" type="submit">搜索</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- 证书列表 -->
|
||||||
<p class="comment" v-if="certs.length == 0">暂时还没有相关的证书。</p>
|
<p class="comment" v-if="certs.length == 0">暂时还没有相关的证书。</p>
|
||||||
<table class="ui table selectable celled" v-if="certs.length > 0">
|
<table class="ui table selectable celled" v-if="certs.length > 0">
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
@@ -80,6 +80,12 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 默认缓存条件 -->
|
||||||
|
<h4>默认缓存条件</h4>
|
||||||
|
<http-cache-refs-box :v-cache-refs="cachePolicy.cacheRefs"></http-cache-refs-box>
|
||||||
|
|
||||||
|
<!-- 使用此策略的集群 -->
|
||||||
<h4>使用此策略的集群</h4>
|
<h4>使用此策略的集群</h4>
|
||||||
<p class="comment" v-if="clusters.length == 0">暂时还没有集群使用此策略。</p>
|
<p class="comment" v-if="clusters.length == 0">暂时还没有集群使用此策略。</p>
|
||||||
<table class="ui table selectable" v-if="clusters.length > 0">
|
<table class="ui table selectable" v-if="clusters.length > 0">
|
||||||
|
|||||||
@@ -1,37 +1,47 @@
|
|||||||
{$layout}
|
{$layout}
|
||||||
|
{$template "policy_menu"}
|
||||||
|
|
||||||
{$template "policy_menu"}
|
<h3>选择集群</h3>
|
||||||
|
<select class="ui dropdown auto-width" v-model="clusterId">
|
||||||
|
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
||||||
|
</select>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
<h3>选择集群</h3>
|
<h3>批量删除</h3>
|
||||||
<select class="ui dropdown auto-width" v-model="clusterId">
|
<p class="comment">可以批量删除一组Key。</p>
|
||||||
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
<form method="post" class="ui form" data-tea-action="$" data-tea-before="before" data-tea-success="success" data-tea-fail="fail" data-tea-done="done">
|
||||||
</select>
|
<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
|
||||||
<div class="ui divider"></div>
|
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
<h3>批量删除</h3>
|
<tr>
|
||||||
<p class="comment">可以批量删除一组Key。</p>
|
<td class="title">操作类型</td>
|
||||||
<form method="post" class="ui form" data-tea-action="$" data-tea-before="before" data-tea-success="success" data-tea-fail="fail" data-tea-done="done">
|
<td>
|
||||||
<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
|
<radio name="type" :v-value="'key'" v-model="type">根据Key</radio>
|
||||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
<radio name="type" :v-value="'prefix'" v-model="type">根据前缀</radio>
|
||||||
<table class="ui table definition selectable">
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>Key列表</td>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<textarea name="keys" rows="10" ref="focus"></textarea>
|
<span v-if="type == 'key'">Key列表</span>
|
||||||
<p class="comment">每行一个Key。</p>
|
<span v-if="type == 'prefix'">Key前缀列表</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
<td>
|
||||||
<tr>
|
<textarea name="keys" rows="10" ref="focus"></textarea>
|
||||||
<td class="title">操作结果</td>
|
<p class="comment" v-if="type == 'key'">每行一个Key,比如是一个完整的URL<code-label>https://example.com/hello/world.html</code-label>。</p>
|
||||||
<td>
|
<p class="comment" v-if="type == 'prefix'">每行一个Key前缀,比如是一个URL前缀<code-label>https://example.com/hello/</code-label>。</p>
|
||||||
<div v-if="isRequesting">数据发送中...</div>
|
</td>
|
||||||
<span class="red" v-if="!isRequesting && !isOk && message.length > 0">失败:{{message}}</span>
|
</tr>
|
||||||
<div v-if="!isRequesting && isOk">
|
<tr>
|
||||||
<span v-if="results.length == 0" class="red">此集群下没有任何可用的节点。</span>
|
<td>操作结果</td>
|
||||||
<div class="ui label tiny" v-for="one in results" :class="{green:one.isOk, red:!one.isOk}" style="margin-bottom: 0.5em">{{one.nodeName}}:{{one.message}}</div>
|
<td>
|
||||||
</div>
|
<div v-if="isRequesting">数据发送中...</div>
|
||||||
</td>
|
<span class="red" v-if="!isRequesting && !isOk && message.length > 0">失败:{{message}}</span>
|
||||||
</tr>
|
<div v-if="!isRequesting && isOk">
|
||||||
</table>
|
<span v-if="results.length == 0" class="red">此集群下没有任何可用的节点。</span>
|
||||||
<submit-btn v-if="!isRequesting">提交</submit-btn>
|
<div class="ui label tiny" v-for="one in results" :class="{green:one.isOk, red:!one.isOk}" style="margin-bottom: 0.5em">{{one.nodeName}}:{{one.message}}</div>
|
||||||
</form>
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn v-if="!isRequesting">提交</submit-btn>
|
||||||
|
</form>
|
||||||
@@ -31,4 +31,9 @@ Tea.context(function () {
|
|||||||
this.done = function () {
|
this.done = function () {
|
||||||
this.isRequesting = false
|
this.isRequesting = false
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* 操作类型
|
||||||
|
*/
|
||||||
|
this.type = "key" // key | prefix
|
||||||
|
})
|
||||||
@@ -94,5 +94,9 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<h4>默认缓存条件</h4>
|
||||||
|
<http-cache-refs-config-box :v-cache-refs="cachePolicy.cacheRefs"></http-cache-refs-config-box>
|
||||||
|
|
||||||
<submit-btn></submit-btn>
|
<submit-btn></submit-btn>
|
||||||
</form>
|
</form>
|
||||||
6
web/views/@default/servers/index.css
Normal file
6
web/views/@default/servers/index.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.ui.message .icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 1em;
|
||||||
|
top: 1.8em;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=index.css.map */
|
||||||
1
web/views/@default/servers/index.css.map
Normal file
1
web/views/@default/servers/index.css.map
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,GAAG,QACF;EACC,kBAAA;EACA,UAAA;EACA,UAAA","file":"index.css"}
|
||||||
@@ -1,6 +1,23 @@
|
|||||||
{$layout}
|
{$layout}
|
||||||
{$template "menu"}
|
{$template "menu"}
|
||||||
|
|
||||||
|
<!-- 错误日志 -->
|
||||||
|
<div v-if="errorLogs.length > 0">
|
||||||
|
<div class="margin"></div>
|
||||||
|
<div class="ui menu tabular attached">
|
||||||
|
<span class="ui item active"><span class="red">需要修复的错误</span></span>
|
||||||
|
</div>
|
||||||
|
<div class="ui segment attached">
|
||||||
|
<div class="ui message error" v-for="log in errorLogs">
|
||||||
|
[{{log.createdTime}}]
|
||||||
|
<a :href="'/servers/server/settings?serverId=' + log.serverId"><span v-if="log.serverName.length > 0">[{{log.serverName}}]</span><span v-else>[服务]</span></a>
|
||||||
|
{{log.description}}
|
||||||
|
<a href="" title="关闭" @click.prevent="fixLog(log.id)"><i class="ui icon remove small"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 搜索表单 -->
|
||||||
<form method="get" class="ui form" action="/servers">
|
<form method="get" class="ui form" action="/servers">
|
||||||
<input type="hidden" name="auditingFlag" :value="auditingFlag"/>
|
<input type="hidden" name="auditingFlag" :value="auditingFlag"/>
|
||||||
<div class="ui margin"></div>
|
<div class="ui margin"></div>
|
||||||
|
|||||||
@@ -46,4 +46,20 @@ Tea.context(function () {
|
|||||||
this.showLatest = function () {
|
this.showLatest = function () {
|
||||||
this.latestVisible = !this.latestVisible
|
this.latestVisible = !this.latestVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误日志相关
|
||||||
|
*/
|
||||||
|
this.fixLog = function (logId) {
|
||||||
|
let that = this
|
||||||
|
teaweb.confirm("确定要关闭此错误提示吗?", function () {
|
||||||
|
that.$post(".fixLog")
|
||||||
|
.params({
|
||||||
|
logId: logId
|
||||||
|
})
|
||||||
|
.success(function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
7
web/views/@default/servers/index.less
Normal file
7
web/views/@default/servers/index.less
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.ui.message {
|
||||||
|
.icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 1em;
|
||||||
|
top: 1.8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
<form class="ui form" data-tea-success="success" data-tea-action="$">
|
<form class="ui form" data-tea-success="success" data-tea-action="$">
|
||||||
<csrf-token></csrf-token>
|
<csrf-token></csrf-token>
|
||||||
|
<input type="hidden" name="matchPrefix" :value="redirect.matchPrefix ? 1 : 0"/>
|
||||||
|
<input type="hidden" name="matchRegexp" :value="redirect.matchRegexp ? 1 : 0"/>
|
||||||
|
|
||||||
<table class="ui table definition selectable">
|
<table class="ui table definition selectable">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -17,15 +19,17 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>匹配模式</td>
|
<td>匹配模式</td>
|
||||||
<td>
|
<td>
|
||||||
<select class="ui dropdown auto-width" name="matchPrefix" v-model="matchPrefix">
|
<select class="ui dropdown auto-width" name="mode" v-model="mode">
|
||||||
<option value="0">精准匹配</option>
|
<option value="equal">精准匹配</option>
|
||||||
<option value="1">匹配前缀</option>
|
<option value="matchPrefix">匹配前缀</option>
|
||||||
|
<option value="matchRegexp">正则匹配</option>
|
||||||
</select>
|
</select>
|
||||||
<p class="comment" v-if="matchPrefix == 0">精准匹配跳转前的URL。</p>
|
<p class="comment" v-if="mode == 'equal'">精准匹配跳转前的URL,即只有访问完全一样的URL才会跳转。</p>
|
||||||
<p class="comment" v-if="matchPrefix == 1">只要URL头部部分包含跳转前URL,即可跳转。</p>
|
<p class="comment" v-if="mode == 'matchPrefix'">只要访问的URL头部部分包含跳转前URL,即可跳转。</p>
|
||||||
|
<p class="comment" v-if="mode == 'matchRegexp'">可以在跳转前URL中使用正则表达式,然后可以在跳转后URL中使用正则表达式中括号的变量,比如<code-label>${1}</code-label>、<code-label>${2}</code-label>等。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="matchPrefix == 1">
|
<tr v-if="mode == 'matchPrefix'">
|
||||||
<td>是否保留URL路径参数</td>
|
<td>是否保留URL路径参数</td>
|
||||||
<td>
|
<td>
|
||||||
<checkbox name="keepRequestURI" value="1" v-model="redirect.keepRequestURI"></checkbox>
|
<checkbox name="keepRequestURI" value="1" v-model="redirect.keepRequestURI"></checkbox>
|
||||||
|
|||||||
@@ -1,17 +1,41 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.isCreating = true
|
this.isCreating = true
|
||||||
if (window.parent.UPDATING_REDIRECT != null) {
|
if (window.parent.UPDATING_REDIRECT != null) {
|
||||||
this.isCreating = false
|
this.isCreating = false
|
||||||
this.redirect = window.parent.UPDATING_REDIRECT
|
this.redirect = window.parent.UPDATING_REDIRECT
|
||||||
} else {
|
} else {
|
||||||
this.redirect = {
|
this.redirect = {
|
||||||
status: 0,
|
status: 0,
|
||||||
beforeURL: "",
|
beforeURL: "",
|
||||||
afterURL: "",
|
afterURL: "",
|
||||||
matchPrefix: false,
|
matchPrefix: false,
|
||||||
keepRequestURI: false
|
matchRegexp: false,
|
||||||
}
|
keepRequestURI: false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.matchPrefix = (this.redirect.matchPrefix ? 1 : 0)
|
this.mode = ""
|
||||||
|
if (this.redirect.matchPrefix) {
|
||||||
|
this.mode = "matchPrefix"
|
||||||
|
} else if (this.redirect.matchRegexp) {
|
||||||
|
this.mode = "matchRegexp"
|
||||||
|
} else {
|
||||||
|
this.mode = "equal"
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$delay(function () {
|
||||||
|
let that = this
|
||||||
|
this.$watch("mode", function (v) {
|
||||||
|
if (v == "matchPrefix") {
|
||||||
|
that.redirect.matchPrefix = true
|
||||||
|
that.redirect.matchRegexp = false
|
||||||
|
} else if (v == "matchRegexp") {
|
||||||
|
that.redirect.matchPrefix = false
|
||||||
|
that.redirect.matchRegexp = true
|
||||||
|
} else {
|
||||||
|
that.redirect.matchPrefix = false
|
||||||
|
that.redirect.matchRegexp = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user