Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee61feb581 | ||
|
|
7f04f1ed62 | ||
|
|
82646c3576 | ||
|
|
b3f62240c4 | ||
|
|
86a5992e8a | ||
|
|
82a731ed06 | ||
|
|
e650529efb | ||
|
|
1de57e124f | ||
|
|
9e72dcc390 | ||
|
|
80019e2071 | ||
|
|
ab7cdcd1b1 | ||
|
|
7afe1e0a30 | ||
|
|
a39eb80214 | ||
|
|
10e2a08cd2 | ||
|
|
6da4949c98 | ||
|
|
4d092f329b | ||
|
|
69c1d35406 | ||
|
|
a256a7328e | ||
|
|
75c8658366 | ||
|
|
c3e68915a3 | ||
|
|
d97f4da7fa | ||
|
|
06e81dbe37 | ||
|
|
4a46aaa880 | ||
|
|
e766372a81 | ||
|
|
c5ee9f095a |
@@ -1,5 +1,17 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
ROOT=$(dirname $0)
|
||||||
|
|
||||||
|
# build all nodes
|
||||||
|
if [ -f $ROOT"/../../EdgeNode/build/build-all-plus.sh" ]; then
|
||||||
|
echo "=============================="
|
||||||
|
echo "build all edge-node"
|
||||||
|
echo "=============================="
|
||||||
|
cd $ROOT"/../../EdgeNode/build"
|
||||||
|
./build-all-plus.sh
|
||||||
|
cd -
|
||||||
|
fi
|
||||||
|
|
||||||
./build.sh linux amd64
|
./build.sh linux amd64
|
||||||
./build.sh linux 386
|
./build.sh linux 386
|
||||||
./build.sh linux arm64
|
./build.sh linux arm64
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ function build() {
|
|||||||
VERSION=$(lookup-version $ROOT/../internal/const/const.go)
|
VERSION=$(lookup-version $ROOT/../internal/const/const.go)
|
||||||
ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip"
|
ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip"
|
||||||
|
|
||||||
# check edge-api
|
# build edge-api
|
||||||
APINodeVersion=$(lookup-version $ROOT"/../../EdgeAPI/internal/const/const.go")
|
APINodeVersion=$(lookup-version $ROOT"/../../EdgeAPI/internal/const/const.go")
|
||||||
echo "building edge-api v${APINodeVersion} ..."
|
echo "building edge-api v${APINodeVersion} ..."
|
||||||
EDGE_API_BUILD_SCRIPT=$ROOT"/../../EdgeAPI/build/build.sh"
|
EDGE_API_BUILD_SCRIPT=$ROOT"/../../EdgeAPI/build/build.sh"
|
||||||
|
|||||||
3
go.mod
3
go.mod
@@ -1,6 +1,6 @@
|
|||||||
module github.com/TeaOSLab/EdgeAdmin
|
module github.com/TeaOSLab/EdgeAdmin
|
||||||
|
|
||||||
go 1.15
|
go 1.16
|
||||||
|
|
||||||
replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
|
replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
|
||||||
|
|
||||||
@@ -9,7 +9,6 @@ require (
|
|||||||
github.com/cespare/xxhash v1.1.0
|
github.com/cespare/xxhash v1.1.0
|
||||||
github.com/go-sql-driver/mysql v1.5.0
|
github.com/go-sql-driver/mysql v1.5.0
|
||||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||||
github.com/golang/protobuf v1.5.2
|
|
||||||
github.com/google/go-cmp v0.5.6 // indirect
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
github.com/iwind/TeaGo v0.0.0-20210720011303-fc255c995afa
|
github.com/iwind/TeaGo v0.0.0-20210720011303-fc255c995afa
|
||||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3
|
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -141,6 +141,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
|
||||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
@@ -164,6 +165,7 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "0.2.7"
|
Version = "0.2.9"
|
||||||
|
|
||||||
ProductName = "Edge Admin"
|
ProductName = "Edge Admin"
|
||||||
ProcessName = "edge-admin"
|
ProcessName = "edge-admin"
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ func (this *RPCClient) NodeGrantRPC() pb.NodeGrantServiceClient {
|
|||||||
return pb.NewNodeGrantServiceClient(this.pickConn())
|
return pb.NewNodeGrantServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) NodeLoginRPC() pb.NodeLoginServiceClient {
|
||||||
|
return pb.NewNodeLoginServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) NodeClusterRPC() pb.NodeClusterServiceClient {
|
func (this *RPCClient) NodeClusterRPC() pb.NodeClusterServiceClient {
|
||||||
return pb.NewNodeClusterServiceClient(this.pickConn())
|
return pb.NewNodeClusterServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -404,6 +408,10 @@ func (this *RPCClient) NSRPC() pb.NSServiceClient {
|
|||||||
return pb.NewNSServiceClient(this.pickConn())
|
return pb.NewNSServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) NSQuestionOptionRPC() pb.NSQuestionOptionServiceClient {
|
||||||
|
return pb.NewNSQuestionOptionServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient {
|
func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient {
|
||||||
return pb.NewMetricItemServiceClient(this.pickConn())
|
return pb.NewMetricItemServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
Offset: page.Offset,
|
Offset: page.Offset,
|
||||||
Size: page.Size,
|
Size: page.Size,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
recipientMaps := []maps.Map{}
|
recipientMaps := []maps.Map{}
|
||||||
for _, recipient := range recipientsResp.MessageRecipients {
|
for _, recipient := range recipientsResp.MessageRecipients {
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
Offset: page.Offset,
|
Offset: page.Offset,
|
||||||
Size: page.Size,
|
Size: page.Size,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
instanceMaps := []maps.Map{}
|
instanceMaps := []maps.Map{}
|
||||||
for _, instance := range instancesResp.MessageMediaInstances {
|
for _, instance := range instancesResp.MessageMediaInstances {
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateNodeAction 创建节点
|
// CreateNodeAction 创建节点
|
||||||
@@ -67,6 +69,22 @@ func (this *CreateNodeAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
this.Data["dnsRoutes"] = dnsRouteMaps
|
this.Data["dnsRoutes"] = dnsRouteMaps
|
||||||
|
|
||||||
|
// API节点列表
|
||||||
|
apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apiNodes := apiNodesResp.Nodes
|
||||||
|
apiEndpoints := []string{}
|
||||||
|
for _, apiNode := range apiNodes {
|
||||||
|
if !apiNode.IsOn {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...)
|
||||||
|
}
|
||||||
|
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,5 +192,57 @@ func (this *CreateNodeAction) RunPost(params struct {
|
|||||||
// 创建日志
|
// 创建日志
|
||||||
defer this.CreateLog(oplogs.LevelInfo, "创建节点 %d", nodeId)
|
defer this.CreateLog(oplogs.LevelInfo, "创建节点 %d", nodeId)
|
||||||
|
|
||||||
|
// 响应数据
|
||||||
|
this.Data["nodeId"] = nodeId
|
||||||
|
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: nodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if nodeResp.Node != nil {
|
||||||
|
var addresses = []string{}
|
||||||
|
for _, addrMap := range ipAddresses {
|
||||||
|
addresses = append(addresses, addrMap.GetString("ip"))
|
||||||
|
}
|
||||||
|
|
||||||
|
var grantMap maps.Map = nil
|
||||||
|
grantId := params.GrantId
|
||||||
|
if grantId > 0 {
|
||||||
|
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if grantResp.NodeGrant != nil && grantResp.NodeGrant.Id > 0 {
|
||||||
|
grantMap = maps.Map{
|
||||||
|
"id": grantResp.NodeGrant.Id,
|
||||||
|
"name": grantResp.NodeGrant.Name,
|
||||||
|
"method": grantResp.NodeGrant.Method,
|
||||||
|
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||||
|
"username": grantResp.NodeGrant.Username,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["node"] = maps.Map{
|
||||||
|
"id": nodeResp.Node.Id,
|
||||||
|
"name": nodeResp.Node.Name,
|
||||||
|
"uniqueId": nodeResp.Node.UniqueId,
|
||||||
|
"secret": nodeResp.Node.Secret,
|
||||||
|
"addresses": addresses,
|
||||||
|
"login": maps.Map{
|
||||||
|
"id": 0,
|
||||||
|
"name": "SSH",
|
||||||
|
"type": "ssh",
|
||||||
|
"params": maps.Map{
|
||||||
|
"grantId": params.GrantId,
|
||||||
|
"host": params.SshHost,
|
||||||
|
"port": params.SshPort,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"grant": grantMap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package cluster
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateNodeInstallAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateNodeInstallAction) RunPost(params struct {
|
||||||
|
NodeId int64
|
||||||
|
SshHost string
|
||||||
|
SshPort int
|
||||||
|
GrantId int64
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("安装节点 %d", params.NodeId)
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("sshHost2", params.SshHost).
|
||||||
|
Require("请填写SSH主机地址").
|
||||||
|
Field("sshPort2", params.SshPort).
|
||||||
|
Gt(0, "请填写SSH主机端口").
|
||||||
|
Lt(65535, "SSH主机端口需要小于65535").
|
||||||
|
Field("grantId", params.GrantId).
|
||||||
|
Gt(0, "请选择SSH登录认证")
|
||||||
|
|
||||||
|
// 查询login
|
||||||
|
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var node = nodeResp.Node
|
||||||
|
if node == nil {
|
||||||
|
this.Fail("找不到要修改的节点")
|
||||||
|
}
|
||||||
|
var loginId int64
|
||||||
|
if node.NodeLogin != nil {
|
||||||
|
loginId = node.NodeLogin.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改节点信息
|
||||||
|
_, err = this.RPC().NodeRPC().UpdateNodeLogin(this.AdminContext(), &pb.UpdateNodeLoginRequest{
|
||||||
|
NodeId: params.NodeId,
|
||||||
|
NodeLogin: &pb.NodeLogin{
|
||||||
|
Id: loginId,
|
||||||
|
Name: "SSH",
|
||||||
|
Type: "ssh",
|
||||||
|
Params: maps.Map{
|
||||||
|
"grantId": params.GrantId,
|
||||||
|
"host": params.SshHost,
|
||||||
|
"port": params.SshPort,
|
||||||
|
}.AsJSON(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始安装
|
||||||
|
_, err = this.RPC().NodeRPC().InstallNode(this.AdminContext(), &pb.InstallNodeRequest{NodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("安装失败:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -27,9 +27,11 @@ func init() {
|
|||||||
Post("/upgradeStatus", new(UpgradeStatusAction)).
|
Post("/upgradeStatus", new(UpgradeStatusAction)).
|
||||||
GetPost("/delete", new(DeleteAction)).
|
GetPost("/delete", new(DeleteAction)).
|
||||||
GetPost("/createNode", new(CreateNodeAction)).
|
GetPost("/createNode", new(CreateNodeAction)).
|
||||||
|
Post("/createNodeInstall", new(CreateNodeInstallAction)).
|
||||||
GetPost("/createBatch", new(CreateBatchAction)).
|
GetPost("/createBatch", new(CreateBatchAction)).
|
||||||
GetPost("/updateNodeSSH", new(UpdateNodeSSHAction)).
|
GetPost("/updateNodeSSH", new(UpdateNodeSSHAction)).
|
||||||
GetPost("/installManual", new(InstallManualAction)).
|
GetPost("/installManual", new(InstallManualAction)).
|
||||||
|
Post("/suggestLoginPorts", new(SuggestLoginPortsAction)).
|
||||||
|
|
||||||
// 节点相关
|
// 节点相关
|
||||||
Prefix("/clusters/cluster/node").
|
Prefix("/clusters/cluster/node").
|
||||||
@@ -58,7 +60,6 @@ func init() {
|
|||||||
// 看板相关
|
// 看板相关
|
||||||
Prefix("/clusters/cluster/boards").
|
Prefix("/clusters/cluster/boards").
|
||||||
Get("", new(boards.IndexAction)).
|
Get("", new(boards.IndexAction)).
|
||||||
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ func (this *InstallManualAction) RunGet(params struct {
|
|||||||
nodeMaps := []maps.Map{}
|
nodeMaps := []maps.Map{}
|
||||||
for _, node := range nodesResp.Nodes {
|
for _, node := range nodesResp.Nodes {
|
||||||
loginParams := maps.Map{}
|
loginParams := maps.Map{}
|
||||||
if node.Login != nil && len(node.Login.Params) > 0 {
|
if node.NodeLogin != nil && len(node.NodeLogin.Params) > 0 {
|
||||||
err := json.Unmarshal(node.Login.Params, &loginParams)
|
err := json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -56,7 +56,7 @@ func (this *InstallManualAction) RunGet(params struct {
|
|||||||
"isOn": node.IsOn,
|
"isOn": node.IsOn,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
"addresses": node.IpAddresses,
|
"addresses": node.IpAddresses,
|
||||||
"login": node.Login,
|
"login": node.NodeLogin,
|
||||||
"loginParams": loginParams,
|
"loginParams": loginParams,
|
||||||
"installStatus": installStatus,
|
"installStatus": installStatus,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ func (this *InstallRemoteAction) RunGet(params struct {
|
|||||||
nodeMaps := []maps.Map{}
|
nodeMaps := []maps.Map{}
|
||||||
for _, node := range nodesResp.Nodes {
|
for _, node := range nodesResp.Nodes {
|
||||||
loginParams := maps.Map{}
|
loginParams := maps.Map{}
|
||||||
if node.Login != nil && len(node.Login.Params) > 0 {
|
if node.NodeLogin != nil && len(node.NodeLogin.Params) > 0 {
|
||||||
err := json.Unmarshal(node.Login.Params, &loginParams)
|
err := json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -58,7 +58,7 @@ func (this *InstallRemoteAction) RunGet(params struct {
|
|||||||
"isOn": node.IsOn,
|
"isOn": node.IsOn,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
"addresses": node.IpAddresses,
|
"addresses": node.IpAddresses,
|
||||||
"login": node.Login,
|
"login": node.NodeLogin,
|
||||||
"loginParams": loginParams,
|
"loginParams": loginParams,
|
||||||
"installStatus": installStatus,
|
"installStatus": installStatus,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -141,10 +141,10 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
|
|
||||||
// 登录信息
|
// 登录信息
|
||||||
var loginMap maps.Map = nil
|
var loginMap maps.Map = nil
|
||||||
if node.Login != nil {
|
if node.NodeLogin != nil {
|
||||||
loginParams := maps.Map{}
|
loginParams := maps.Map{}
|
||||||
if len(node.Login.Params) > 0 {
|
if len(node.NodeLogin.Params) > 0 {
|
||||||
err = json.Unmarshal(node.Login.Params, &loginParams)
|
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -165,14 +165,15 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
"name": grantResp.NodeGrant.Name,
|
"name": grantResp.NodeGrant.Name,
|
||||||
"method": grantResp.NodeGrant.Method,
|
"method": grantResp.NodeGrant.Method,
|
||||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||||
|
"username": grantResp.NodeGrant.Username,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loginMap = maps.Map{
|
loginMap = maps.Map{
|
||||||
"id": node.Login.Id,
|
"id": node.NodeLogin.Id,
|
||||||
"name": node.Login.Name,
|
"name": node.NodeLogin.Name,
|
||||||
"type": node.Login.Type,
|
"type": node.NodeLogin.Type,
|
||||||
"params": loginParams,
|
"params": loginParams,
|
||||||
"grant": grantMap,
|
"grant": grantMap,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 安装节点
|
// InstallAction 安装节点
|
||||||
type InstallAction struct {
|
type InstallAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,7 @@ func (this *InstallAction) RunGet(params struct {
|
|||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始安装
|
// RunPost 开始安装
|
||||||
func (this *InstallAction) RunPost(params struct {
|
func (this *InstallAction) RunPost(params struct {
|
||||||
NodeId int64
|
NodeId int64
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ func (this *LogsAction) RunGet(params struct {
|
|||||||
Offset: page.Offset,
|
Offset: page.Offset,
|
||||||
Size: page.Size,
|
Size: page.Size,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
logs := []maps.Map{}
|
logs := []maps.Map{}
|
||||||
for _, log := range logsResp.NodeLogs {
|
for _, log := range logsResp.NodeLogs {
|
||||||
|
|||||||
@@ -126,10 +126,10 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
|
|
||||||
// 登录信息
|
// 登录信息
|
||||||
var loginMap maps.Map = nil
|
var loginMap maps.Map = nil
|
||||||
if node.Login != nil {
|
if node.NodeLogin != nil {
|
||||||
loginParams := maps.Map{}
|
loginParams := maps.Map{}
|
||||||
if len(node.Login.Params) > 0 {
|
if len(node.NodeLogin.Params) > 0 {
|
||||||
err = json.Unmarshal(node.Login.Params, &loginParams)
|
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -150,14 +150,15 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
"name": grantResp.NodeGrant.Name,
|
"name": grantResp.NodeGrant.Name,
|
||||||
"method": grantResp.NodeGrant.Method,
|
"method": grantResp.NodeGrant.Method,
|
||||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||||
|
"username": grantResp.NodeGrant.Username,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loginMap = maps.Map{
|
loginMap = maps.Map{
|
||||||
"id": node.Login.Id,
|
"id": node.NodeLogin.Id,
|
||||||
"name": node.Login.Name,
|
"name": node.NodeLogin.Name,
|
||||||
"type": node.Login.Type,
|
"type": node.NodeLogin.Type,
|
||||||
"params": loginParams,
|
"params": loginParams,
|
||||||
"grant": grantMap,
|
"grant": grantMap,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package cluster
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SuggestLoginPortsAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SuggestLoginPortsAction) RunPost(params struct {
|
||||||
|
Host string
|
||||||
|
}) {
|
||||||
|
portsResp, err := this.RPC().NodeLoginRPC().FindNodeLoginSuggestPorts(this.AdminContext(), &pb.FindNodeLoginSuggestPortsRequest{Host: params.Host})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(portsResp.Ports) == 0 {
|
||||||
|
this.Data["ports"] = []int32{}
|
||||||
|
} else {
|
||||||
|
this.Data["ports"] = portsResp.Ports
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(portsResp.AvailablePorts) == 0 {
|
||||||
|
this.Data["availablePorts"] = []int32{}
|
||||||
|
} else {
|
||||||
|
this.Data["availablePorts"] = portsResp.AvailablePorts
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -36,6 +36,11 @@ func (this *UpdateNodeSSHAction) RunGet(params struct {
|
|||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
}
|
}
|
||||||
|
if nodeResp.Node.NodeCluster != nil {
|
||||||
|
this.Data["clusterId"] = nodeResp.Node.NodeCluster.Id
|
||||||
|
} else {
|
||||||
|
this.Data["clusterId"] = 0
|
||||||
|
}
|
||||||
|
|
||||||
// SSH
|
// SSH
|
||||||
loginParams := maps.Map{
|
loginParams := maps.Map{
|
||||||
@@ -44,10 +49,10 @@ func (this *UpdateNodeSSHAction) RunGet(params struct {
|
|||||||
"grantId": 0,
|
"grantId": 0,
|
||||||
}
|
}
|
||||||
this.Data["loginId"] = 0
|
this.Data["loginId"] = 0
|
||||||
if node.Login != nil {
|
if node.NodeLogin != nil {
|
||||||
this.Data["loginId"] = node.Login.Id
|
this.Data["loginId"] = node.NodeLogin.Id
|
||||||
if len(node.Login.Params) > 0 {
|
if len(node.NodeLogin.Params) > 0 {
|
||||||
err = json.Unmarshal(node.Login.Params, &loginParams)
|
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ func (this *UpgradeRemoteAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
for _, node := range resp.Nodes {
|
for _, node := range resp.Nodes {
|
||||||
loginParams := maps.Map{}
|
loginParams := maps.Map{}
|
||||||
if node.Node.Login != nil && len(node.Node.Login.Params) > 0 {
|
if node.Node.NodeLogin != nil && len(node.Node.NodeLogin.Params) > 0 {
|
||||||
err := json.Unmarshal(node.Node.Login.Params, &loginParams)
|
err := json.Unmarshal(node.Node.NodeLogin.Params, &loginParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -46,7 +46,7 @@ func (this *UpgradeRemoteAction) RunGet(params struct {
|
|||||||
"arch": node.Arch,
|
"arch": node.Arch,
|
||||||
"oldVersion": node.OldVersion,
|
"oldVersion": node.OldVersion,
|
||||||
"newVersion": node.NewVersion,
|
"newVersion": node.NewVersion,
|
||||||
"login": node.Node.Login,
|
"login": node.Node.NodeLogin,
|
||||||
"loginParams": loginParams,
|
"loginParams": loginParams,
|
||||||
"addresses": node.Node.IpAddresses,
|
"addresses": node.Node.IpAddresses,
|
||||||
"installStatus": node.Node.InstallStatus,
|
"installStatus": node.Node.InstallStatus,
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ func (this *SelectPopupAction) Init() {
|
|||||||
this.Nav("", "", "")
|
this.Nav("", "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *SelectPopupAction) RunGet(params struct{}) {
|
func (this *SelectPopupAction) RunGet(params struct {
|
||||||
|
NodeClusterId int64
|
||||||
|
NsClusterId int64
|
||||||
|
}) {
|
||||||
// 所有的认证
|
// 所有的认证
|
||||||
grantsResp, err := this.RPC().NodeGrantRPC().FindAllEnabledNodeGrants(this.AdminContext(), &pb.FindAllEnabledNodeGrantsRequest{})
|
grantsResp, err := this.RPC().NodeGrantRPC().FindAllEnabledNodeGrants(this.AdminContext(), &pb.FindAllEnabledNodeGrantsRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -37,6 +40,28 @@ func (this *SelectPopupAction) RunGet(params struct{}) {
|
|||||||
}
|
}
|
||||||
this.Data["grants"] = grantMaps
|
this.Data["grants"] = grantMaps
|
||||||
|
|
||||||
|
// 推荐的认证
|
||||||
|
suggestGrantsResp, err := this.RPC().NodeGrantRPC().FindSuggestNodeGrants(this.AdminContext(), &pb.FindSuggestNodeGrantsRequest{
|
||||||
|
NodeClusterId: params.NodeClusterId,
|
||||||
|
NsClusterId: params.NsClusterId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var suggestGrantMaps = []maps.Map{}
|
||||||
|
for _, grant := range suggestGrantsResp.NodeGrants {
|
||||||
|
suggestGrantMaps = append(suggestGrantMaps, maps.Map{
|
||||||
|
"id": grant.Id,
|
||||||
|
"name": grant.Name,
|
||||||
|
"method": grant.Method,
|
||||||
|
"methodName": grantutils.FindGrantMethodName(grant.Method),
|
||||||
|
"username": grant.Username,
|
||||||
|
"description": grant.Description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["suggestGrants"] = suggestGrantMaps
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
Offset: page.Offset,
|
Offset: page.Offset,
|
||||||
Size: page.Size,
|
Size: page.Size,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
logs := []maps.Map{}
|
logs := []maps.Map{}
|
||||||
for _, log := range logsResp.NodeLogs {
|
for _, log := range logsResp.NodeLogs {
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
ParamAccessKeyId string
|
ParamAccessKeyId string
|
||||||
ParamAccessKeySecret string
|
ParamAccessKeySecret string
|
||||||
|
|
||||||
|
// HuaweiDNS
|
||||||
|
ParamHuaweiAccessKeyId string
|
||||||
|
ParamHuaweiAccessKeySecret string
|
||||||
|
|
||||||
// DNS.COM
|
// DNS.COM
|
||||||
ParamApiKey string
|
ParamApiKey string
|
||||||
ParamApiSecret string
|
ParamApiSecret string
|
||||||
@@ -111,6 +115,15 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
|
|
||||||
apiParams["accessKeyId"] = params.ParamAccessKeyId
|
apiParams["accessKeyId"] = params.ParamAccessKeyId
|
||||||
apiParams["accessKeySecret"] = params.ParamAccessKeySecret
|
apiParams["accessKeySecret"] = params.ParamAccessKeySecret
|
||||||
|
case "huaweiDNS":
|
||||||
|
params.Must.
|
||||||
|
Field("paramHuaweiAccessKeyId", params.ParamHuaweiAccessKeyId).
|
||||||
|
Require("请输入AccessKeyId").
|
||||||
|
Field("paramHuaweiAccessKeySecret", params.ParamHuaweiAccessKeySecret).
|
||||||
|
Require("请输入AccessKeySecret")
|
||||||
|
|
||||||
|
apiParams["accessKeyId"] = params.ParamHuaweiAccessKeyId
|
||||||
|
apiParams["accessKeySecret"] = params.ParamHuaweiAccessKeySecret
|
||||||
case "dnscom":
|
case "dnscom":
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("paramApiKey", params.ParamApiKey).
|
Field("paramApiKey", params.ParamApiKey).
|
||||||
|
|||||||
@@ -96,6 +96,10 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
ParamAccessKeyId string
|
ParamAccessKeyId string
|
||||||
ParamAccessKeySecret string
|
ParamAccessKeySecret string
|
||||||
|
|
||||||
|
// HuaweiDNS
|
||||||
|
ParamHuaweiAccessKeyId string
|
||||||
|
ParamHuaweiAccessKeySecret string
|
||||||
|
|
||||||
// DNS.COM
|
// DNS.COM
|
||||||
ParamApiKey string
|
ParamApiKey string
|
||||||
ParamApiSecret string
|
ParamApiSecret string
|
||||||
@@ -142,6 +146,15 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
|
|
||||||
apiParams["accessKeyId"] = params.ParamAccessKeyId
|
apiParams["accessKeyId"] = params.ParamAccessKeyId
|
||||||
apiParams["accessKeySecret"] = params.ParamAccessKeySecret
|
apiParams["accessKeySecret"] = params.ParamAccessKeySecret
|
||||||
|
case "huaweiDNS":
|
||||||
|
params.Must.
|
||||||
|
Field("paramHuaweiAccessKeyId", params.ParamHuaweiAccessKeyId).
|
||||||
|
Require("请输入AccessKeyId").
|
||||||
|
Field("paramHuaweiAccessKeySecret", params.ParamHuaweiAccessKeySecret).
|
||||||
|
Require("请输入AccessKeySecret")
|
||||||
|
|
||||||
|
apiParams["accessKeyId"] = params.ParamHuaweiAccessKeyId
|
||||||
|
apiParams["accessKeySecret"] = params.ParamHuaweiAccessKeySecret
|
||||||
case "dnscom":
|
case "dnscom":
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("paramApiKey", params.ParamApiKey).
|
Field("paramApiKey", params.ParamApiKey).
|
||||||
|
|||||||
@@ -56,19 +56,26 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.Data["token"] = stringutil.Md5(TokenSalt+timestamp) + timestamp
|
this.Data["token"] = stringutil.Md5(TokenSalt+timestamp) + timestamp
|
||||||
this.Data["from"] = params.From
|
this.Data["from"] = params.From
|
||||||
|
|
||||||
config, err := configloaders.LoadAdminUIConfig()
|
uiConfig, err := configloaders.LoadAdminUIConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.Data["systemName"] = config.AdminSystemName
|
this.Data["systemName"] = uiConfig.AdminSystemName
|
||||||
this.Data["showVersion"] = config.ShowVersion
|
this.Data["showVersion"] = uiConfig.ShowVersion
|
||||||
if len(config.Version) > 0 {
|
if len(uiConfig.Version) > 0 {
|
||||||
this.Data["version"] = config.Version
|
this.Data["version"] = uiConfig.Version
|
||||||
} else {
|
} else {
|
||||||
this.Data["version"] = teaconst.Version
|
this.Data["version"] = teaconst.Version
|
||||||
}
|
}
|
||||||
this.Data["faviconFileId"] = config.FaviconFileId
|
this.Data["faviconFileId"] = uiConfig.FaviconFileId
|
||||||
|
|
||||||
|
securityConfig, err := configloaders.LoadSecurityConfig()
|
||||||
|
if err != nil {
|
||||||
|
this.Data["rememberLogin"] = false
|
||||||
|
} else {
|
||||||
|
this.Data["rememberLogin"] = securityConfig.AllowRememberLogin
|
||||||
|
}
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
|
|
||||||
messages = append(messages, maps.Map{
|
messages = append(messages, maps.Map{
|
||||||
"id": message.Id,
|
"id": message.Id,
|
||||||
|
"role": message.Role,
|
||||||
"isRead": message.IsRead,
|
"isRead": message.IsRead,
|
||||||
"body": message.Body,
|
"body": message.Body,
|
||||||
"level": message.Level,
|
"level": message.Level,
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
"error": node.InstallStatus.Error,
|
"error": node.InstallStatus.Error,
|
||||||
},
|
},
|
||||||
"status": maps.Map{
|
"status": maps.Map{
|
||||||
"isActive": status.IsActive,
|
"isActive": node.IsActive,
|
||||||
"updatedAt": status.UpdatedAt,
|
"updatedAt": status.UpdatedAt,
|
||||||
"hostname": status.Hostname,
|
"hostname": status.Hostname,
|
||||||
"cpuUsage": status.CPUUsage,
|
"cpuUsage": status.CPUUsage,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ func init() {
|
|||||||
GetPost("/createNode", new(CreateNodeAction)).
|
GetPost("/createNode", new(CreateNodeAction)).
|
||||||
Post("/deleteNode", new(DeleteNodeAction)).
|
Post("/deleteNode", new(DeleteNodeAction)).
|
||||||
Get("/upgradeRemote", new(UpgradeRemoteAction)).
|
Get("/upgradeRemote", new(UpgradeRemoteAction)).
|
||||||
|
GetPost("/updateNodeSSH", new(UpdateNodeSSHAction)).
|
||||||
|
|
||||||
// 节点相关
|
// 节点相关
|
||||||
Prefix("/ns/clusters/cluster/node").
|
Prefix("/ns/clusters/cluster/node").
|
||||||
@@ -30,7 +31,8 @@ func init() {
|
|||||||
GetPost("/install", new(node.InstallAction)).
|
GetPost("/install", new(node.InstallAction)).
|
||||||
Post("/status", new(node.StatusAction)).
|
Post("/status", new(node.StatusAction)).
|
||||||
Post("/updateInstallStatus", new(node.UpdateInstallStatusAction)).
|
Post("/updateInstallStatus", new(node.UpdateInstallStatusAction)).
|
||||||
|
Post("/start", new(node.StartAction)).
|
||||||
|
Post("/stop", new(node.StopAction)).
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
@@ -102,6 +103,46 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.Data["newVersion"] = ""
|
this.Data["newVersion"] = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 登录信息
|
||||||
|
var loginMap maps.Map = nil
|
||||||
|
if node.NodeLogin != nil {
|
||||||
|
loginParams := maps.Map{}
|
||||||
|
if len(node.NodeLogin.Params) > 0 {
|
||||||
|
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grantMap := maps.Map{}
|
||||||
|
grantId := loginParams.GetInt64("grantId")
|
||||||
|
if grantId > 0 {
|
||||||
|
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if grantResp.NodeGrant != nil {
|
||||||
|
grantMap = maps.Map{
|
||||||
|
"id": grantResp.NodeGrant.Id,
|
||||||
|
"name": grantResp.NodeGrant.Name,
|
||||||
|
"method": grantResp.NodeGrant.Method,
|
||||||
|
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||||
|
"username": grantResp.NodeGrant.Username,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loginMap = maps.Map{
|
||||||
|
"id": node.NodeLogin.Id,
|
||||||
|
"name": node.NodeLogin.Name,
|
||||||
|
"type": node.NodeLogin.Type,
|
||||||
|
"params": loginParams,
|
||||||
|
"grant": grantMap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
this.Data["node"] = maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
@@ -114,7 +155,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
"isOn": node.IsOn,
|
"isOn": node.IsOn,
|
||||||
|
|
||||||
"status": maps.Map{
|
"status": maps.Map{
|
||||||
"isActive": status.IsActive,
|
"isActive": node.IsActive && status.IsActive,
|
||||||
"updatedAt": status.UpdatedAt,
|
"updatedAt": status.UpdatedAt,
|
||||||
"hostname": status.Hostname,
|
"hostname": status.Hostname,
|
||||||
"cpuUsage": status.CPUUsage,
|
"cpuUsage": status.CPUUsage,
|
||||||
@@ -131,6 +172,8 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
|
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
|
||||||
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
|
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"login": loginMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StartAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StartAction) RunPost(params struct {
|
||||||
|
NodeId int64
|
||||||
|
}) {
|
||||||
|
resp, err := this.RPC().NSNodeRPC().StartNSNode(this.AdminContext(), &pb.StartNSNodeRequest{NsNodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建日志
|
||||||
|
defer this.CreateLog(oplogs.LevelInfo, "远程启动节点 %d", params.NodeId)
|
||||||
|
|
||||||
|
if resp.IsOk {
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Fail("启动失败:" + resp.Error)
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StopAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StopAction) RunPost(params struct {
|
||||||
|
NodeId int64
|
||||||
|
}) {
|
||||||
|
resp, err := this.RPC().NSNodeRPC().StopNSNode(this.AdminContext(), &pb.StopNSNodeRequest{NsNodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建日志
|
||||||
|
defer this.CreateLog(oplogs.LevelInfo, "远程停止节点 %d", params.NodeId)
|
||||||
|
|
||||||
|
if resp.IsOk {
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Fail("执行失败:" + resp.Error)
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
@@ -63,12 +64,53 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 登录信息
|
||||||
|
var loginMap maps.Map = nil
|
||||||
|
if node.NodeLogin != nil {
|
||||||
|
loginParams := maps.Map{}
|
||||||
|
if len(node.NodeLogin.Params) > 0 {
|
||||||
|
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grantMap := maps.Map{}
|
||||||
|
grantId := loginParams.GetInt64("grantId")
|
||||||
|
if grantId > 0 {
|
||||||
|
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if grantResp.NodeGrant != nil {
|
||||||
|
grantMap = maps.Map{
|
||||||
|
"id": grantResp.NodeGrant.Id,
|
||||||
|
"name": grantResp.NodeGrant.Name,
|
||||||
|
"method": grantResp.NodeGrant.Method,
|
||||||
|
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||||
|
"username": grantResp.NodeGrant.Username,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loginMap = maps.Map{
|
||||||
|
"id": node.NodeLogin.Id,
|
||||||
|
"name": node.NodeLogin.Name,
|
||||||
|
"type": node.NodeLogin.Type,
|
||||||
|
"params": loginParams,
|
||||||
|
"grant": grantMap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
this.Data["node"] = maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
"ipAddresses": ipAddressMaps,
|
"ipAddresses": ipAddressMaps,
|
||||||
"cluster": clusterMap,
|
"cluster": clusterMap,
|
||||||
"isOn": node.IsOn,
|
"isOn": node.IsOn,
|
||||||
|
"login": loginMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 所有集群
|
// 所有集群
|
||||||
@@ -93,7 +135,11 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *UpdateAction) RunPost(params struct {
|
func (this *UpdateAction) RunPost(params struct {
|
||||||
LoginId int64
|
LoginId int64
|
||||||
|
GrantId int64
|
||||||
|
SshHost string
|
||||||
|
SshPort int
|
||||||
|
|
||||||
NodeId int64
|
NodeId int64
|
||||||
Name string
|
Name string
|
||||||
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
||||||
@@ -139,12 +185,25 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
this.Fail("请至少输入一个IP地址")
|
this.Fail("请至少输入一个IP地址")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 检查登录授权
|
||||||
|
loginInfo := &pb.NodeLogin{
|
||||||
|
Id: params.LoginId,
|
||||||
|
Name: "SSH",
|
||||||
|
Type: "ssh",
|
||||||
|
Params: maps.Map{
|
||||||
|
"grantId": params.GrantId,
|
||||||
|
"host": params.SshHost,
|
||||||
|
"port": params.SshPort,
|
||||||
|
}.AsJSON(),
|
||||||
|
}
|
||||||
|
|
||||||
// 保存
|
// 保存
|
||||||
_, err = this.RPC().NSNodeRPC().UpdateNSNode(this.AdminContext(), &pb.UpdateNSNodeRequest{
|
_, err = this.RPC().NSNodeRPC().UpdateNSNode(this.AdminContext(), &pb.UpdateNSNodeRequest{
|
||||||
NsNodeId: params.NodeId,
|
NsNodeId: params.NodeId,
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
NsClusterId: params.ClusterId,
|
NsClusterId: params.ClusterId,
|
||||||
IsOn: params.IsOn,
|
IsOn: params.IsOn,
|
||||||
|
NodeLogin: loginInfo,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
accessLogRef := &dnsconfigs.AccessLogRef{}
|
accessLogRef := &dnsconfigs.NSAccessLogRef{}
|
||||||
if len(accessLogResp.AccessLogJSON) > 0 {
|
if len(accessLogResp.AccessLogJSON) > 0 {
|
||||||
err = json.Unmarshal(accessLogResp.AccessLogJSON, accessLogRef)
|
err = json.Unmarshal(accessLogResp.AccessLogJSON, accessLogRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -50,7 +50,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
}) {
|
}) {
|
||||||
defer this.CreateLogInfo("修改域名服务集群 %d 访问日志配置", params.ClusterId)
|
defer this.CreateLogInfo("修改域名服务集群 %d 访问日志配置", params.ClusterId)
|
||||||
|
|
||||||
ref := &dnsconfigs.AccessLogRef{}
|
ref := &dnsconfigs.NSAccessLogRef{}
|
||||||
err := json.Unmarshal(params.AccessLogJSON, ref)
|
err := json.Unmarshal(params.AccessLogJSON, ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("数据格式错误:" + err.Error())
|
this.Fail("数据格式错误:" + err.Error())
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package cluster
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateNodeSSHAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateNodeSSHAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateNodeSSHAction) RunGet(params struct {
|
||||||
|
NodeId int64
|
||||||
|
}) {
|
||||||
|
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if nodeResp.NsNode == nil {
|
||||||
|
this.NotFound("node", params.NodeId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
node := nodeResp.NsNode
|
||||||
|
this.Data["node"] = maps.Map{
|
||||||
|
"id": node.Id,
|
||||||
|
"name": node.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeResp.NsNode.NsCluster != nil {
|
||||||
|
this.Data["clusterId"] = nodeResp.NsNode.NsCluster.Id
|
||||||
|
} else {
|
||||||
|
this.Data["clusterId"] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSH
|
||||||
|
loginParams := maps.Map{
|
||||||
|
"host": "",
|
||||||
|
"port": "",
|
||||||
|
"grantId": 0,
|
||||||
|
}
|
||||||
|
this.Data["loginId"] = 0
|
||||||
|
if node.NodeLogin != nil {
|
||||||
|
this.Data["loginId"] = node.NodeLogin.Id
|
||||||
|
if len(node.NodeLogin.Params) > 0 {
|
||||||
|
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Data["params"] = loginParams
|
||||||
|
|
||||||
|
// 认证信息
|
||||||
|
grantId := loginParams.GetInt64("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.NodeGrant != nil {
|
||||||
|
grantMap = maps.Map{
|
||||||
|
"id": grantResp.NodeGrant.Id,
|
||||||
|
"name": grantResp.NodeGrant.Name,
|
||||||
|
"method": grantResp.NodeGrant.Method,
|
||||||
|
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Data["grant"] = grantMap
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateNodeSSHAction) RunPost(params struct {
|
||||||
|
NodeId int64
|
||||||
|
LoginId int64
|
||||||
|
SshHost string
|
||||||
|
SshPort int
|
||||||
|
GrantId int64
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
params.Must.
|
||||||
|
Field("sshHost", params.SshHost).
|
||||||
|
Require("请输入SSH主机地址").
|
||||||
|
Field("sshPort", params.SshPort).
|
||||||
|
Gt(0, "SSH主机端口需要大于0").
|
||||||
|
Lt(65535, "SSH主机端口需要小于65535")
|
||||||
|
|
||||||
|
if params.GrantId <= 0 {
|
||||||
|
this.Fail("需要选择或填写至少一个认证信息")
|
||||||
|
}
|
||||||
|
|
||||||
|
login := &pb.NodeLogin{
|
||||||
|
Id: params.LoginId,
|
||||||
|
Name: "SSH",
|
||||||
|
Type: "ssh",
|
||||||
|
Params: maps.Map{
|
||||||
|
"grantId": params.GrantId,
|
||||||
|
"host": params.SshHost,
|
||||||
|
"port": params.SshPort,
|
||||||
|
}.AsJSON(),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := this.RPC().NSNodeRPC().UpdateNSNodeLogin(this.AdminContext(), &pb.UpdateNSNodeLoginRequest{
|
||||||
|
NsNodeId: params.NodeId,
|
||||||
|
NodeLogin: login,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建日志
|
||||||
|
defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d 配置", params.NodeId)
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ func (this *CreateAction) Init() {
|
|||||||
|
|
||||||
func (this *CreateAction) RunGet(params struct{}) {
|
func (this *CreateAction) RunGet(params struct{}) {
|
||||||
// 默认的访问日志设置
|
// 默认的访问日志设置
|
||||||
this.Data["accessLogRef"] = &dnsconfigs.AccessLogRef{
|
this.Data["accessLogRef"] = &dnsconfigs.NSAccessLogRef{
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
Require("请输入集群名称")
|
Require("请输入集群名称")
|
||||||
|
|
||||||
// 校验访问日志设置
|
// 校验访问日志设置
|
||||||
ref := &dnsconfigs.AccessLogRef{}
|
ref := &dnsconfigs.NSAccessLogRef{}
|
||||||
err := json.Unmarshal(params.AccessLogJSON, ref)
|
err := json.Unmarshal(params.AccessLogJSON, ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("数据格式错误:" + err.Error())
|
this.Fail("数据格式错误:" + err.Error())
|
||||||
|
|||||||
96
internal/web/actions/default/ns/domains/index.go
Normal file
96
internal/web/actions/default/ns/domains/index.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package domains
|
||||||
|
|
||||||
|
import (
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.FirstMenu("domain")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
UserId int64
|
||||||
|
Keyword string
|
||||||
|
}) {
|
||||||
|
if !teaconst.IsPlus {
|
||||||
|
this.RedirectURL("/")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["clusterId"] = params.ClusterId
|
||||||
|
this.Data["userId"] = params.UserId
|
||||||
|
this.Data["keyword"] = params.Keyword
|
||||||
|
|
||||||
|
// 集群数量
|
||||||
|
countClustersResp, err := this.RPC().NSClusterRPC().CountAllEnabledNSClusters(this.AdminContext(), &pb.CountAllEnabledNSClustersRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["countClusters"] = countClustersResp.Count
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
countResp, err := this.RPC().NSDomainRPC().CountAllEnabledNSDomains(this.AdminContext(), &pb.CountAllEnabledNSDomainsRequest{
|
||||||
|
UserId: params.UserId,
|
||||||
|
NsClusterId: params.ClusterId,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
page := this.NewPage(countResp.Count)
|
||||||
|
|
||||||
|
// 列表
|
||||||
|
domainsResp, err := this.RPC().NSDomainRPC().ListEnabledNSDomains(this.AdminContext(), &pb.ListEnabledNSDomainsRequest{
|
||||||
|
UserId: params.UserId,
|
||||||
|
NsClusterId: params.ClusterId,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
domainMaps := []maps.Map{}
|
||||||
|
for _, domain := range domainsResp.NsDomains {
|
||||||
|
// 集群信息
|
||||||
|
var clusterMap maps.Map
|
||||||
|
if domain.NsCluster != nil {
|
||||||
|
clusterMap = maps.Map{
|
||||||
|
"id": domain.NsCluster.Id,
|
||||||
|
"name": domain.NsCluster.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户信息
|
||||||
|
var userMap maps.Map
|
||||||
|
if domain.User != nil {
|
||||||
|
userMap = maps.Map{
|
||||||
|
"id": domain.User.Id,
|
||||||
|
"username": domain.User.Username,
|
||||||
|
"fullname": domain.User.Fullname,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
domainMaps = append(domainMaps, maps.Map{
|
||||||
|
"id": domain.Id,
|
||||||
|
"name": domain.Name,
|
||||||
|
"isOn": domain.IsOn,
|
||||||
|
"cluster": clusterMap,
|
||||||
|
"user": userMap,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["domains"] = domainMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -54,7 +54,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
Value string
|
Value string
|
||||||
Ttl int32
|
Ttl int32
|
||||||
Description string
|
Description string
|
||||||
RouteIds []int64
|
RouteCodes []string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
@@ -76,13 +76,13 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createResp, err := this.RPC().NSRecordRPC().CreateNSRecord(this.AdminContext(), &pb.CreateNSRecordRequest{
|
createResp, err := this.RPC().NSRecordRPC().CreateNSRecord(this.AdminContext(), &pb.CreateNSRecordRequest{
|
||||||
NsDomainId: params.DomainId,
|
NsDomainId: params.DomainId,
|
||||||
Description: params.Description,
|
Description: params.Description,
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
Type: params.Type,
|
Type: params.Type,
|
||||||
Value: params.Value,
|
Value: params.Value,
|
||||||
Ttl: params.Ttl,
|
Ttl: params.Ttl,
|
||||||
NsRouteIds: params.RouteIds,
|
NsRouteCodes: params.RouteCodes,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
DomainId int64
|
DomainId int64
|
||||||
Type string
|
Type string
|
||||||
Keyword string
|
Keyword string
|
||||||
RouteId int64
|
RouteCode string
|
||||||
}) {
|
}) {
|
||||||
// 初始化域名信息
|
// 初始化域名信息
|
||||||
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||||
@@ -33,14 +33,14 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
|
|
||||||
this.Data["type"] = params.Type
|
this.Data["type"] = params.Type
|
||||||
this.Data["keyword"] = params.Keyword
|
this.Data["keyword"] = params.Keyword
|
||||||
this.Data["routeId"] = params.RouteId
|
this.Data["routeCode"] = params.RouteCode
|
||||||
|
|
||||||
// 记录
|
// 记录
|
||||||
countResp, err := this.RPC().NSRecordRPC().CountAllEnabledNSRecords(this.AdminContext(), &pb.CountAllEnabledNSRecordsRequest{
|
countResp, err := this.RPC().NSRecordRPC().CountAllEnabledNSRecords(this.AdminContext(), &pb.CountAllEnabledNSRecordsRequest{
|
||||||
NsDomainId: params.DomainId,
|
NsDomainId: params.DomainId,
|
||||||
Type: params.Type,
|
Type: params.Type,
|
||||||
NsRouteId: params.RouteId,
|
NsRouteCode: params.RouteCode,
|
||||||
Keyword: params.Keyword,
|
Keyword: params.Keyword,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
@@ -51,12 +51,12 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.Data["page"] = page.AsHTML()
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
recordsResp, err := this.RPC().NSRecordRPC().ListEnabledNSRecords(this.AdminContext(), &pb.ListEnabledNSRecordsRequest{
|
recordsResp, err := this.RPC().NSRecordRPC().ListEnabledNSRecords(this.AdminContext(), &pb.ListEnabledNSRecordsRequest{
|
||||||
NsDomainId: params.DomainId,
|
NsDomainId: params.DomainId,
|
||||||
Type: params.Type,
|
Type: params.Type,
|
||||||
NsRouteId: params.RouteId,
|
NsRouteCode: params.RouteCode,
|
||||||
Keyword: params.Keyword,
|
Keyword: params.Keyword,
|
||||||
Offset: page.Offset,
|
Offset: page.Offset,
|
||||||
Size: page.Size,
|
Size: page.Size,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -33,11 +33,6 @@ func (this *UpdatePopupAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
routeIds := []int64{}
|
|
||||||
for _, route := range record.NsRoutes {
|
|
||||||
routeIds = append(routeIds, route.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["record"] = maps.Map{
|
this.Data["record"] = maps.Map{
|
||||||
"id": record.Id,
|
"id": record.Id,
|
||||||
"name": record.Name,
|
"name": record.Name,
|
||||||
@@ -47,7 +42,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
|
|||||||
"weight": record.Weight,
|
"weight": record.Weight,
|
||||||
"description": record.Description,
|
"description": record.Description,
|
||||||
"isOn": record.IsOn,
|
"isOn": record.IsOn,
|
||||||
"routeIds": routeIds,
|
"routes": record.NsRoutes,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 域名信息
|
// 域名信息
|
||||||
@@ -83,7 +78,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
Ttl int32
|
Ttl int32
|
||||||
Description string
|
Description string
|
||||||
IsOn bool
|
IsOn bool
|
||||||
RouteIds []int64
|
RouteCodes []string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
@@ -102,14 +97,14 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err := this.RPC().NSRecordRPC().UpdateNSRecord(this.AdminContext(), &pb.UpdateNSRecordRequest{
|
_, err := this.RPC().NSRecordRPC().UpdateNSRecord(this.AdminContext(), &pb.UpdateNSRecordRequest{
|
||||||
NsRecordId: params.RecordId,
|
NsRecordId: params.RecordId,
|
||||||
Description: params.Description,
|
Description: params.Description,
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
Type: params.Type,
|
Type: params.Type,
|
||||||
Value: params.Value,
|
Value: params.Value,
|
||||||
Ttl: params.Ttl,
|
Ttl: params.Ttl,
|
||||||
IsOn: params.IsOn,
|
IsOn: params.IsOn,
|
||||||
NsRouteIds: params.RouteIds,
|
NsRouteCodes: params.RouteCodes,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
package ns
|
package ns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -12,85 +15,113 @@ type IndexAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) Init() {
|
func (this *IndexAction) Init() {
|
||||||
this.FirstMenu("index")
|
this.Nav("", "", "dns")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct {
|
func (this *IndexAction) RunGet(params struct{}) {
|
||||||
ClusterId int64
|
resp, err := this.RPC().NSRPC().ComposeNSBoard(this.AdminContext(), &pb.ComposeNSBoardRequest{})
|
||||||
UserId int64
|
|
||||||
Keyword string
|
|
||||||
}) {
|
|
||||||
if !teaconst.IsPlus {
|
|
||||||
this.RedirectURL("/")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["clusterId"] = params.ClusterId
|
|
||||||
this.Data["userId"] = params.UserId
|
|
||||||
this.Data["keyword"] = params.Keyword
|
|
||||||
|
|
||||||
// 集群数量
|
|
||||||
countClustersResp, err := this.RPC().NSClusterRPC().CountAllEnabledNSClusters(this.AdminContext(), &pb.CountAllEnabledNSClustersRequest{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.Data["countClusters"] = countClustersResp.Count
|
this.Data["board"] = maps.Map{
|
||||||
|
"countDomains": resp.CountNSDomains,
|
||||||
// 分页
|
"countRecords": resp.CountNSRecords,
|
||||||
countResp, err := this.RPC().NSDomainRPC().CountAllEnabledNSDomains(this.AdminContext(), &pb.CountAllEnabledNSDomainsRequest{
|
"countClusters": resp.CountNSClusters,
|
||||||
UserId: params.UserId,
|
"countNodes": resp.CountNSNodes,
|
||||||
NsClusterId: params.ClusterId,
|
"countOfflineNodes": resp.CountOfflineNSNodes,
|
||||||
Keyword: params.Keyword,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
page := this.NewPage(countResp.Count)
|
|
||||||
|
|
||||||
// 列表
|
// 流量排行
|
||||||
domainsResp, err := this.RPC().NSDomainRPC().ListEnabledNSDomains(this.AdminContext(), &pb.ListEnabledNSDomainsRequest{
|
{
|
||||||
UserId: params.UserId,
|
var statMaps = []maps.Map{}
|
||||||
NsClusterId: params.ClusterId,
|
for _, stat := range resp.HourlyTrafficStats {
|
||||||
Keyword: params.Keyword,
|
statMaps = append(statMaps, maps.Map{
|
||||||
Offset: page.Offset,
|
"day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
|
||||||
Size: page.Size,
|
"hour": stat.Hour[8:],
|
||||||
})
|
"countRequests": stat.CountRequests,
|
||||||
if err != nil {
|
"bytes": stat.Bytes,
|
||||||
this.ErrorPage(err)
|
})
|
||||||
return
|
|
||||||
}
|
|
||||||
domainMaps := []maps.Map{}
|
|
||||||
for _, domain := range domainsResp.NsDomains {
|
|
||||||
// 集群信息
|
|
||||||
var clusterMap maps.Map
|
|
||||||
if domain.NsCluster != nil {
|
|
||||||
clusterMap = maps.Map{
|
|
||||||
"id": domain.NsCluster.Id,
|
|
||||||
"name": domain.NsCluster.Name,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
this.Data["hourlyStats"] = statMaps
|
||||||
// 用户信息
|
}
|
||||||
var userMap maps.Map
|
|
||||||
if domain.User != nil {
|
{
|
||||||
userMap = maps.Map{
|
var statMaps = []maps.Map{}
|
||||||
"id": domain.User.Id,
|
for _, stat := range resp.DailyTrafficStats {
|
||||||
"username": domain.User.Username,
|
statMaps = append(statMaps, maps.Map{
|
||||||
"fullname": domain.User.Fullname,
|
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
||||||
}
|
"countRequests": stat.CountRequests,
|
||||||
}
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
domainMaps = append(domainMaps, maps.Map{
|
}
|
||||||
"id": domain.Id,
|
this.Data["dailyStats"] = statMaps
|
||||||
"name": domain.Name,
|
}
|
||||||
"isOn": domain.IsOn,
|
|
||||||
"cluster": clusterMap,
|
// 域名排行
|
||||||
"user": userMap,
|
{
|
||||||
})
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.TopNSDomainStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"domainId": stat.NsDomainId,
|
||||||
|
"domainName": stat.NsDomainName,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["topDomainStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点排行
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.TopNSNodeStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"clusterId": stat.NsClusterId,
|
||||||
|
"nodeId": stat.NsNodeId,
|
||||||
|
"nodeName": stat.NsNodeName,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["topNodeStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPU
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.CpuNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["cpuValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.MemoryNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["memoryValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.LoadNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["loadValues"] = statMaps
|
||||||
}
|
}
|
||||||
this.Data["domains"] = domainMaps
|
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/keys"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/keys"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/records"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/records"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/settings"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/iwind/TeaGo"
|
"github.com/iwind/TeaGo"
|
||||||
)
|
)
|
||||||
@@ -19,6 +20,8 @@ func init() {
|
|||||||
|
|
||||||
// 域名相关
|
// 域名相关
|
||||||
Prefix("/ns/domains").
|
Prefix("/ns/domains").
|
||||||
|
Data("teaSubMenu", "domain").
|
||||||
|
Get("", new(domains.IndexAction)).
|
||||||
GetPost("/create", new(domains.CreateAction)).
|
GetPost("/create", new(domains.CreateAction)).
|
||||||
Post("/delete", new(domains.DeleteAction)).
|
Post("/delete", new(domains.DeleteAction)).
|
||||||
Get("/domain", new(domains.DomainAction)).
|
Get("/domain", new(domains.DomainAction)).
|
||||||
@@ -27,6 +30,7 @@ func init() {
|
|||||||
|
|
||||||
// 域名密钥
|
// 域名密钥
|
||||||
Prefix("/ns/domains/keys").
|
Prefix("/ns/domains/keys").
|
||||||
|
Data("teaSubMenu", "domain").
|
||||||
Get("", new(keys.IndexAction)).
|
Get("", new(keys.IndexAction)).
|
||||||
GetPost("/createPopup", new(keys.CreatePopupAction)).
|
GetPost("/createPopup", new(keys.CreatePopupAction)).
|
||||||
GetPost("/updatePopup", new(keys.UpdatePopupAction)).
|
GetPost("/updatePopup", new(keys.UpdatePopupAction)).
|
||||||
@@ -40,6 +44,9 @@ func init() {
|
|||||||
GetPost("/updatePopup", new(records.UpdatePopupAction)).
|
GetPost("/updatePopup", new(records.UpdatePopupAction)).
|
||||||
Post("/delete", new(records.DeleteAction)).
|
Post("/delete", new(records.DeleteAction)).
|
||||||
|
|
||||||
|
// 设置
|
||||||
|
Prefix("/ns/settings").
|
||||||
|
Get("", new(settings.IndexAction)).
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ package clusters
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OptionsAction struct {
|
type OptionsAction struct {
|
||||||
@@ -17,6 +19,18 @@ func (this *OptionsAction) RunPost(params struct {
|
|||||||
DomainId int64
|
DomainId int64
|
||||||
UserId int64
|
UserId int64
|
||||||
}) {
|
}) {
|
||||||
|
var routeMaps = []maps.Map{}
|
||||||
|
|
||||||
|
// 默认线路
|
||||||
|
for _, route := range dnsconfigs.AllDefaultRoutes {
|
||||||
|
routeMaps = append(routeMaps, maps.Map{
|
||||||
|
"name": route.Name,
|
||||||
|
"code": route.Code,
|
||||||
|
"type": "default",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义
|
||||||
routesResp, err := this.RPC().NSRouteRPC().FindAllEnabledNSRoutes(this.AdminContext(), &pb.FindAllEnabledNSRoutesRequest{
|
routesResp, err := this.RPC().NSRouteRPC().FindAllEnabledNSRoutes(this.AdminContext(), &pb.FindAllEnabledNSRoutesRequest{
|
||||||
NsClusterId: params.ClusterId,
|
NsClusterId: params.ClusterId,
|
||||||
NsDomainId: params.DomainId,
|
NsDomainId: params.DomainId,
|
||||||
@@ -27,13 +41,45 @@ func (this *OptionsAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
routeMaps := []maps.Map{}
|
|
||||||
for _, route := range routesResp.NsRoutes {
|
for _, route := range routesResp.NsRoutes {
|
||||||
|
if len(route.Code) == 0 {
|
||||||
|
route.Code = "id:" + types.String(route.Id)
|
||||||
|
}
|
||||||
|
|
||||||
routeMaps = append(routeMaps, maps.Map{
|
routeMaps = append(routeMaps, maps.Map{
|
||||||
"id": route.Id,
|
|
||||||
"name": route.Name,
|
"name": route.Name,
|
||||||
|
"code": route.Code,
|
||||||
|
"type": "user",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 运营商
|
||||||
|
for _, route := range dnsconfigs.AllDefaultISPRoutes {
|
||||||
|
routeMaps = append(routeMaps, maps.Map{
|
||||||
|
"name": route.Name,
|
||||||
|
"code": route.Code,
|
||||||
|
"type": "isp",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 中国
|
||||||
|
for _, route := range dnsconfigs.AllDefaultChinaProvinceRoutes {
|
||||||
|
routeMaps = append(routeMaps, maps.Map{
|
||||||
|
"name": route.Name,
|
||||||
|
"code": route.Code,
|
||||||
|
"type": "china",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全球
|
||||||
|
for _, route := range dnsconfigs.AllDefaultWorldRegionRoutes {
|
||||||
|
routeMaps = append(routeMaps, maps.Map{
|
||||||
|
"name": route.Name,
|
||||||
|
"code": route.Code,
|
||||||
|
"type": "world",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["routes"] = routeMaps
|
this.Data["routes"] = routeMaps
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
|
|||||||
77
internal/web/actions/default/ns/settings/accesslogs/index.go
Normal file
77
internal/web/actions/default/ns/settings/accesslogs/index.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package accesslogs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
this.SecondMenu("accessLog")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct{}) {
|
||||||
|
resp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{
|
||||||
|
Code: systemconfigs.SettingCodeNSAccessLogSetting,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = &dnsconfigs.NSAccessLogRef{}
|
||||||
|
if len(resp.ValueJSON) > 0 {
|
||||||
|
err = json.Unmarshal(resp.ValueJSON, config)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config.IsOn = true
|
||||||
|
config.LogMissingDomains = true
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["config"] = config
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunPost(params struct {
|
||||||
|
AccessLogJSON []byte
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
// 校验配置
|
||||||
|
var config = &dnsconfigs.NSAccessLogRef{}
|
||||||
|
err := json.Unmarshal(params.AccessLogJSON, config)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("配置解析失败:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = config.Init()
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("配置校验失败:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = this.RPC().SysSettingRPC().UpdateSysSetting(this.AdminContext(), &pb.UpdateSysSettingRequest{
|
||||||
|
Code: systemconfigs.SettingCodeNSAccessLogSetting,
|
||||||
|
ValueJSON: params.AccessLogJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
23
internal/web/actions/default/ns/settings/accesslogs/init.go
Normal file
23
internal/web/actions/default/ns/settings/accesslogs/init.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package accesslogs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/settings/settingutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
|
"github.com/iwind/TeaGo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
|
server.
|
||||||
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNS)).
|
||||||
|
Helper(new(settingutils.Helper)).
|
||||||
|
Data("teaMenu", "ns").
|
||||||
|
Data("teaSubMenu", "setting").
|
||||||
|
Prefix("/ns/settings/accesslogs").
|
||||||
|
GetPost("", new(IndexAction)).
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
17
internal/web/actions/default/ns/settings/index.go
Normal file
17
internal/web/actions/default/ns/settings/index.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package settings
|
||||||
|
|
||||||
|
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct{}) {
|
||||||
|
this.RedirectURL("/ns/settings/accesslogs")
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package settingutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Helper struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
|
||||||
|
var action = actionPtr.Object()
|
||||||
|
secondMenuItem := action.Data.GetString("secondMenuItem")
|
||||||
|
action.Data["leftMenuItems"] = this.createSettingMenu(secondMenuItem)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Helper) createSettingMenu(selectedItem string) (items []maps.Map) {
|
||||||
|
return []maps.Map{
|
||||||
|
{
|
||||||
|
"name": "访问日志",
|
||||||
|
"url": "/ns/settings/accesslogs",
|
||||||
|
"isActive": selectedItem == "accessLog",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
156
internal/web/actions/default/ns/test/index.go
Normal file
156
internal/web/actions/default/ns/test/index.go
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
"net"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct{}) {
|
||||||
|
// 集群列表
|
||||||
|
clustersResp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var clusterMaps = []maps.Map{}
|
||||||
|
for _, cluster := range clustersResp.NsClusters {
|
||||||
|
if !cluster.IsOn {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
countNodesResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{
|
||||||
|
NsClusterId: cluster.Id,
|
||||||
|
InstallState: 0,
|
||||||
|
ActiveState: 0,
|
||||||
|
Keyword: "",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var countNodes = countNodesResp.Count
|
||||||
|
if countNodes <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
clusterMaps = append(clusterMaps, maps.Map{
|
||||||
|
"id": cluster.Id,
|
||||||
|
"name": cluster.Name,
|
||||||
|
"countNodes": countNodes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["clusters"] = clusterMaps
|
||||||
|
|
||||||
|
// 记录类型
|
||||||
|
this.Data["recordTypes"] = dnsconfigs.FindAllRecordTypeDefinitions()
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunPost(params struct {
|
||||||
|
NodeId int64
|
||||||
|
Domain string
|
||||||
|
Type string
|
||||||
|
Ip string
|
||||||
|
ClientIP string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var node = nodeResp.NsNode
|
||||||
|
if node == nil {
|
||||||
|
this.Fail("找不到要测试的节点")
|
||||||
|
}
|
||||||
|
|
||||||
|
var isOk = false
|
||||||
|
var errMsg string
|
||||||
|
var isNetError = false
|
||||||
|
var result string
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
this.Data["isOk"] = isOk
|
||||||
|
this.Data["err"] = errMsg
|
||||||
|
this.Data["isNetErr"] = isNetError
|
||||||
|
this.Data["result"] = result
|
||||||
|
this.Success()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if !domainutils.ValidateDomainFormat(params.Domain) {
|
||||||
|
errMsg = "域名格式错误"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
recordType, ok := dns.StringToType[params.Type]
|
||||||
|
if !ok {
|
||||||
|
errMsg = "不支持此记录类型"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params.ClientIP) > 0 && net.ParseIP(params.ClientIP) == nil {
|
||||||
|
errMsg = "客户端IP格式不正确"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var optionId int64
|
||||||
|
if len(params.ClientIP) > 0 {
|
||||||
|
optionResp, err := this.RPC().NSQuestionOptionRPC().CreateNSQuestionOption(this.AdminContext(), &pb.CreateNSQuestionOptionRequest{
|
||||||
|
Name: "setRemoteAddr",
|
||||||
|
ValuesJSON: maps.Map{"ip": params.ClientIP}.AsJSON(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
optionId = optionResp.NsQuestionOptionId
|
||||||
|
defer func() {
|
||||||
|
_, err = this.RPC().NSQuestionOptionRPC().DeleteNSQuestionOption(this.AdminContext(), &pb.DeleteNSQuestionOptionRequest{NsQuestionOptionId: optionId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
c := new(dns.Client)
|
||||||
|
m := new(dns.Msg)
|
||||||
|
var domain = params.Domain + "."
|
||||||
|
if optionId > 0 {
|
||||||
|
domain = "$" + types.String(optionId) + "-" + domain
|
||||||
|
}
|
||||||
|
m.SetQuestion(domain, recordType)
|
||||||
|
r, _, err := c.Exchange(m, params.Ip+":53")
|
||||||
|
if err != nil {
|
||||||
|
errMsg = "解析过程中出错:" + err.Error()
|
||||||
|
|
||||||
|
// 是否为网络错误
|
||||||
|
if regexp.MustCompile(`timeout|connect`).MatchString(err.Error()) {
|
||||||
|
isNetError = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result = r.String()
|
||||||
|
result = regexp.MustCompile(`\$\d+-`).ReplaceAllString(result, "")
|
||||||
|
isOk = true
|
||||||
|
}
|
||||||
20
internal/web/actions/default/ns/test/init.go
Normal file
20
internal/web/actions/default/ns/test/init.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
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.AdminModuleCodeNS)).
|
||||||
|
Data("teaMenu", "ns").
|
||||||
|
Data("teaSubMenu", "test").
|
||||||
|
Prefix("/ns/test").
|
||||||
|
GetPost("", new(IndexAction)).
|
||||||
|
Post("/nodeOptions", new(NodeOptionsAction)).
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
59
internal/web/actions/default/ns/test/nodeOptions.go
Normal file
59
internal/web/actions/default/ns/test/nodeOptions.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
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 NodeOptionsAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *NodeOptionsAction) RunPost(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
}) {
|
||||||
|
nodesResp, err := this.RPC().NSNodeRPC().FindAllEnabledNSNodesWithNSClusterId(this.AdminContext(), &pb.FindAllEnabledNSNodesWithNSClusterIdRequest{NsClusterId: params.ClusterId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodeMaps = []maps.Map{}
|
||||||
|
for _, node := range nodesResp.NsNodes {
|
||||||
|
if !node.IsOn {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
addressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
|
||||||
|
NodeId: node.Id,
|
||||||
|
Role: nodeconfigs.NodeRoleDNS,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var addresses = addressesResp.Addresses
|
||||||
|
if len(addresses) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var addrs = []string{}
|
||||||
|
for _, addr := range addresses {
|
||||||
|
if addr.CanAccess {
|
||||||
|
addrs = append(addrs, addr.Ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeMaps = append(nodeMaps, maps.Map{
|
||||||
|
"id": node.Id,
|
||||||
|
"name": node.Name,
|
||||||
|
"addrs": addrs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["nodes"] = nodeMaps
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
40
internal/web/actions/default/servers/ipbox/addIP.go
Normal file
40
internal/web/actions/default/servers/ipbox/addIP.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package ipbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AddIPAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *AddIPAction) RunPost(params struct {
|
||||||
|
ListId int64
|
||||||
|
Ip string
|
||||||
|
}) {
|
||||||
|
var ipType = "ipv4"
|
||||||
|
if strings.Contains(params.Ip, ":") {
|
||||||
|
ipType = "ipv6"
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
|
||||||
|
IpListId: params.ListId,
|
||||||
|
IpFrom: params.Ip,
|
||||||
|
IpTo: "",
|
||||||
|
ExpiredAt: time.Now().Unix() + 86400, // TODO 可以自定义时间
|
||||||
|
Reason: "从IPBox中加入名单",
|
||||||
|
Type: ipType,
|
||||||
|
EventLevel: "critical",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ package ipbox
|
|||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -22,10 +23,62 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}) {
|
}) {
|
||||||
this.Data["ip"] = params.Ip
|
this.Data["ip"] = params.Ip
|
||||||
|
|
||||||
|
// IP信息
|
||||||
|
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: params.Ip})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if regionResp.IpRegion != nil {
|
||||||
|
this.Data["regions"] = regionResp.IpRegion.Summary
|
||||||
|
} else {
|
||||||
|
this.Data["regions"] = ""
|
||||||
|
}
|
||||||
|
this.Data["isp"] = regionResp.IpRegion.Isp
|
||||||
|
|
||||||
|
// IP列表
|
||||||
|
ipListResp, err := this.RPC().IPListRPC().FindEnabledIPListContainsIP(this.AdminContext(), &pb.FindEnabledIPListContainsIPRequest{Ip: params.Ip})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var ipListMaps = []maps.Map{}
|
||||||
|
for _, ipList := range ipListResp.IpLists {
|
||||||
|
ipListMaps = append(ipListMaps, maps.Map{
|
||||||
|
"id": ipList.Id,
|
||||||
|
"name": ipList.Name,
|
||||||
|
"type": ipList.Type,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["ipLists"] = ipListMaps
|
||||||
|
|
||||||
|
// 所有公用的IP列表
|
||||||
|
publicBlackIPListResp, err := this.RPC().IPListRPC().ListEnabledIPLists(this.AdminContext(), &pb.ListEnabledIPListsRequest{
|
||||||
|
Type: "black",
|
||||||
|
IsPublic: true,
|
||||||
|
Keyword: "",
|
||||||
|
Offset: 0,
|
||||||
|
Size: 10, // TODO 将来考虑到支持更多的黑名单
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var publicBlackIPListMaps = []maps.Map{}
|
||||||
|
for _, ipList := range publicBlackIPListResp.IpLists {
|
||||||
|
publicBlackIPListMaps = append(publicBlackIPListMaps, maps.Map{
|
||||||
|
"id": ipList.Id,
|
||||||
|
"name": ipList.Name,
|
||||||
|
"type": ipList.Type,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["publicBlackIPLists"] = publicBlackIPListMaps
|
||||||
|
|
||||||
|
// 访问日志
|
||||||
accessLogsResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
accessLogsResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||||
Day: timeutil.Format("Ymd"),
|
Day: timeutil.Format("Ymd"),
|
||||||
Keyword: "ip:" + params.Ip,
|
Ip: params.Ip,
|
||||||
Size: 10,
|
Size: 20,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
@@ -35,9 +88,9 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
if len(accessLogs) == 0 {
|
if len(accessLogs) == 0 {
|
||||||
// 查询昨天
|
// 查询昨天
|
||||||
accessLogsResp, err = this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
accessLogsResp, err = this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||||
Day: timeutil.Format("Ymd", time.Now().AddDate(0, 0, -1)),
|
Day: timeutil.Format("Ymd", time.Now().AddDate(0, 0, -1)),
|
||||||
Keyword: "ip:" + params.Ip,
|
Ip: params.Ip,
|
||||||
Size: 10,
|
Size: 20,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ func init() {
|
|||||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
|
||||||
Prefix("/servers/ipbox").
|
Prefix("/servers/ipbox").
|
||||||
Get("", new(IndexAction)).
|
Get("", new(IndexAction)).
|
||||||
|
Post("/addIP", new(AddIPAction)).
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,15 @@
|
|||||||
package iplists
|
package iplists
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/csv"
|
||||||
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"github.com/tealeg/xlsx/v3"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,10 +25,55 @@ func (this *ExportDataAction) Init() {
|
|||||||
|
|
||||||
func (this *ExportDataAction) RunGet(params struct {
|
func (this *ExportDataAction) RunGet(params struct {
|
||||||
ListId int64
|
ListId int64
|
||||||
|
Format string
|
||||||
}) {
|
}) {
|
||||||
defer this.CreateLogInfo("导出IP名单 %d", params.ListId)
|
defer this.CreateLogInfo("导出IP名单 %d", params.ListId)
|
||||||
|
|
||||||
resp := &pb.ListIPItemsWithListIdResponse{}
|
var err error
|
||||||
|
var ext = ""
|
||||||
|
var jsonMaps = []maps.Map{}
|
||||||
|
var xlsxFile *xlsx.File
|
||||||
|
var xlsxSheet *xlsx.Sheet
|
||||||
|
var csvWriter *csv.Writer
|
||||||
|
var csvBuffer *bytes.Buffer
|
||||||
|
|
||||||
|
var data []byte
|
||||||
|
|
||||||
|
switch params.Format {
|
||||||
|
case "xlsx":
|
||||||
|
ext = ".xlsx"
|
||||||
|
xlsxFile = xlsx.NewFile()
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
xlsxSheet, err = xlsxFile.AddSheet("IP名单")
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
row := xlsxSheet.AddRow()
|
||||||
|
row.SetHeight(26)
|
||||||
|
row.AddCell().SetValue("开始IP")
|
||||||
|
row.AddCell().SetValue("结束IP")
|
||||||
|
row.AddCell().SetValue("过期时间戳")
|
||||||
|
row.AddCell().SetValue("类型")
|
||||||
|
row.AddCell().SetValue("级别")
|
||||||
|
row.AddCell().SetValue("备注")
|
||||||
|
case "csv":
|
||||||
|
ext = ".csv"
|
||||||
|
csvBuffer = &bytes.Buffer{}
|
||||||
|
csvWriter = csv.NewWriter(csvBuffer)
|
||||||
|
case "txt":
|
||||||
|
ext = ".txt"
|
||||||
|
case "json":
|
||||||
|
ext = ".json"
|
||||||
|
default:
|
||||||
|
this.WriteString("请选择正确的导出格式")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var offset int64 = 0
|
var offset int64 = 0
|
||||||
var size int64 = 1000
|
var size int64 = 1000
|
||||||
for {
|
for {
|
||||||
@@ -40,18 +90,60 @@ func (this *ExportDataAction) RunGet(params struct {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
for _, item := range itemsResp.IpItems {
|
for _, item := range itemsResp.IpItems {
|
||||||
resp.IpItems = append(resp.IpItems, item)
|
switch params.Format {
|
||||||
|
case "xlsx":
|
||||||
|
row := xlsxSheet.AddRow()
|
||||||
|
row.SetHeight(26)
|
||||||
|
row.AddCell().SetValue(item.IpFrom)
|
||||||
|
row.AddCell().SetValue(item.IpTo)
|
||||||
|
row.AddCell().SetValue(types.String(item.ExpiredAt))
|
||||||
|
row.AddCell().SetValue(item.Type)
|
||||||
|
row.AddCell().SetValue(item.EventLevel)
|
||||||
|
row.AddCell().SetValue(item.Reason)
|
||||||
|
case "csv":
|
||||||
|
err = csvWriter.Write([]string{item.IpFrom, item.IpTo, types.String(item.ExpiredAt), item.Type, item.EventLevel, item.Reason})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "txt":
|
||||||
|
data = append(data, item.IpFrom+","+item.IpTo+","+types.String(item.ExpiredAt)+","+item.Type+","+item.EventLevel+","+item.Reason...)
|
||||||
|
data = append(data, '\n')
|
||||||
|
case "json":
|
||||||
|
jsonMaps = append(jsonMaps, maps.Map{
|
||||||
|
"ipFrom": item.IpFrom,
|
||||||
|
"ipTo": item.IpTo,
|
||||||
|
"expiredAt": item.ExpiredAt,
|
||||||
|
"type": item.Type,
|
||||||
|
"eventLevel": item.EventLevel,
|
||||||
|
"reason": item.Reason,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
offset += size
|
offset += size
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := proto.Marshal(resp)
|
switch params.Format {
|
||||||
if err != nil {
|
case "xlsx":
|
||||||
this.ErrorPage(err)
|
var buf = &bytes.Buffer{}
|
||||||
return
|
err = xlsxFile.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data = buf.Bytes()
|
||||||
|
case "csv":
|
||||||
|
csvWriter.Flush()
|
||||||
|
data = csvBuffer.Bytes()
|
||||||
|
case "json":
|
||||||
|
data, err = json.Marshal(jsonMaps)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.AddHeader("Content-Disposition", "attachment; filename=\"ip-list-"+numberutils.FormatInt64(params.ListId)+".data\";")
|
this.AddHeader("Content-Disposition", "attachment; filename=\"ip-list-"+numberutils.FormatInt64(params.ListId)+ext+"\";")
|
||||||
this.AddHeader("Content-Length", strconv.Itoa(len(data)))
|
this.AddHeader("Content-Length", strconv.Itoa(len(data)))
|
||||||
this.Write(data)
|
this.Write(data)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,19 @@
|
|||||||
package iplists
|
package iplists
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/csv"
|
||||||
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"github.com/tealeg/xlsx/v3"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ImportAction struct {
|
type ImportAction struct {
|
||||||
@@ -51,20 +60,92 @@ func (this *ImportAction) RunPost(params struct {
|
|||||||
this.Fail("请选择要导入的IP文件")
|
this.Fail("请选择要导入的IP文件")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查文件扩展名
|
||||||
|
if !regexp.MustCompile(`(?i)\.(xlsx|csv|json|txt)$`).MatchString(params.File.Filename) {
|
||||||
|
this.Fail("不支持当前格式的文件导入")
|
||||||
|
}
|
||||||
|
|
||||||
|
var ext = strings.ToLower(params.File.Ext)
|
||||||
|
|
||||||
data, err := params.File.Read()
|
data, err := params.File.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp := &pb.ListIPItemsWithListIdResponse{}
|
|
||||||
err = proto.Unmarshal(data, resp)
|
var countIgnore = 0
|
||||||
if err != nil {
|
var items = []*pb.IPItem{}
|
||||||
this.Fail("导入失败,文件格式错误:" + err.Error())
|
switch ext {
|
||||||
|
case ".xlsx":
|
||||||
|
file, err := xlsx.OpenBinary(data)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("Excel读取错误:" + err.Error())
|
||||||
|
}
|
||||||
|
if len(file.Sheets) > 0 {
|
||||||
|
var sheet = file.Sheets[0]
|
||||||
|
err = sheet.ForEachRow(func(r *xlsx.Row) error {
|
||||||
|
var values = []string{}
|
||||||
|
err = r.ForEachCell(func(c *xlsx.Cell) error {
|
||||||
|
values = append(values, c.Value)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(values) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if values[0] == "开始IP" || values[0] == "IP" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
item := this.createItemFromValues(values, &countIgnore)
|
||||||
|
if item != nil {
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("Excel读取错误:" + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ".csv":
|
||||||
|
reader := csv.NewReader(bytes.NewBuffer(data))
|
||||||
|
for {
|
||||||
|
values, err := reader.Read()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
this.Fail("CSV读取错误:" + err.Error())
|
||||||
|
}
|
||||||
|
item := this.createItemFromValues(values, &countIgnore)
|
||||||
|
if item != nil {
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ".json":
|
||||||
|
err = json.Unmarshal(data, &items)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("导入失败:" + err.Error())
|
||||||
|
}
|
||||||
|
case ".txt":
|
||||||
|
lines := bytes.Split(data, []byte{'\n'})
|
||||||
|
for _, line := range lines {
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
item := this.createItemFromValues(strings.SplitN(string(line), ",", 6), &countIgnore)
|
||||||
|
if item != nil {
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var count = 0
|
var count = 0
|
||||||
var countIgnore = 0
|
|
||||||
for _, item := range resp.IpItems {
|
lists.Reverse(items)
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
_, err = this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
|
_, err = this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
|
||||||
IpListId: params.ListId,
|
IpListId: params.ListId,
|
||||||
IpFrom: item.IpFrom,
|
IpFrom: item.IpFrom,
|
||||||
@@ -85,3 +166,48 @@ func (this *ImportAction) RunPost(params struct {
|
|||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *ImportAction) createItemFromValues(values []string, countIgnore *int) *pb.IPItem {
|
||||||
|
// ipFrom, ipTo, expiredAt, type, eventType, reason
|
||||||
|
|
||||||
|
var item = &pb.IPItem{}
|
||||||
|
switch len(values) {
|
||||||
|
case 1:
|
||||||
|
item.IpFrom = values[0]
|
||||||
|
case 2:
|
||||||
|
item.IpFrom = values[0]
|
||||||
|
item.IpTo = values[1]
|
||||||
|
case 3:
|
||||||
|
item.IpFrom = values[0]
|
||||||
|
item.IpTo = values[1]
|
||||||
|
item.ExpiredAt = types.Int64(values[2])
|
||||||
|
case 4:
|
||||||
|
item.IpFrom = values[0]
|
||||||
|
item.IpTo = values[1]
|
||||||
|
item.ExpiredAt = types.Int64(values[2])
|
||||||
|
item.Type = values[3]
|
||||||
|
case 5:
|
||||||
|
item.IpFrom = values[0]
|
||||||
|
item.IpTo = values[1]
|
||||||
|
item.ExpiredAt = types.Int64(values[2])
|
||||||
|
item.Type = values[3]
|
||||||
|
item.EventLevel = values[4]
|
||||||
|
case 6:
|
||||||
|
item.IpFrom = values[0]
|
||||||
|
item.IpTo = values[1]
|
||||||
|
item.ExpiredAt = types.Int64(values[2])
|
||||||
|
item.Type = values[3]
|
||||||
|
item.EventLevel = values[4]
|
||||||
|
item.Reason = values[5]
|
||||||
|
}
|
||||||
|
|
||||||
|
if net.ParseIP(item.IpFrom) == nil {
|
||||||
|
*countIgnore++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(item.IpTo) > 0 && net.ParseIP(item.IpTo) == nil {
|
||||||
|
*countIgnore++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|||||||
127
internal/web/actions/default/servers/logs/index.go
Normal file
127
internal/web/actions/default/servers/logs/index.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
Day string
|
||||||
|
Keyword string
|
||||||
|
Ip string
|
||||||
|
Domain string
|
||||||
|
HasError int
|
||||||
|
|
||||||
|
RequestId string
|
||||||
|
ServerId int64
|
||||||
|
}) {
|
||||||
|
if len(params.Day) == 0 {
|
||||||
|
params.Day = timeutil.Format("Y-m-d")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["serverId"] = 0
|
||||||
|
this.Data["path"] = this.Request.URL.Path
|
||||||
|
this.Data["day"] = params.Day
|
||||||
|
this.Data["keyword"] = params.Keyword
|
||||||
|
this.Data["ip"] = params.Ip
|
||||||
|
this.Data["domain"] = params.Domain
|
||||||
|
this.Data["accessLogs"] = []interface{}{}
|
||||||
|
this.Data["hasError"] = params.HasError
|
||||||
|
|
||||||
|
day := params.Day
|
||||||
|
ipList := []string{}
|
||||||
|
|
||||||
|
if len(day) > 0 && regexp.MustCompile(`\d{4}-\d{2}-\d{2}`).MatchString(day) {
|
||||||
|
day = strings.ReplaceAll(day, "-", "")
|
||||||
|
size := int64(10)
|
||||||
|
|
||||||
|
this.Data["hasError"] = params.HasError
|
||||||
|
|
||||||
|
resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||||
|
RequestId: params.RequestId,
|
||||||
|
ServerId: params.ServerId,
|
||||||
|
HasError: params.HasError > 0,
|
||||||
|
Day: day,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Ip: params.Ip,
|
||||||
|
Domain: params.Domain,
|
||||||
|
Size: size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.HttpAccessLogs) == 0 {
|
||||||
|
this.Data["accessLogs"] = []interface{}{}
|
||||||
|
} else {
|
||||||
|
this.Data["accessLogs"] = resp.HttpAccessLogs
|
||||||
|
for _, accessLog := range resp.HttpAccessLogs {
|
||||||
|
if len(accessLog.RemoteAddr) > 0 {
|
||||||
|
if !lists.ContainsString(ipList, accessLog.RemoteAddr) {
|
||||||
|
ipList = append(ipList, accessLog.RemoteAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Data["hasMore"] = resp.HasMore
|
||||||
|
this.Data["nextRequestId"] = resp.RequestId
|
||||||
|
|
||||||
|
// 上一个requestId
|
||||||
|
this.Data["hasPrev"] = false
|
||||||
|
this.Data["lastRequestId"] = ""
|
||||||
|
if len(params.RequestId) > 0 {
|
||||||
|
this.Data["hasPrev"] = true
|
||||||
|
prevResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||||
|
RequestId: params.RequestId,
|
||||||
|
ServerId: params.ServerId,
|
||||||
|
HasError: params.HasError > 0,
|
||||||
|
Day: day,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Ip: params.Ip,
|
||||||
|
Domain: params.Domain,
|
||||||
|
Size: size,
|
||||||
|
Reverse: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if int64(len(prevResp.HttpAccessLogs)) == size {
|
||||||
|
this.Data["lastRequestId"] = prevResp.RequestId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据IP查询区域
|
||||||
|
regionMap := map[string]string{} // ip => region
|
||||||
|
if len(ipList) > 0 {
|
||||||
|
resp, err := this.RPC().IPLibraryRPC().LookupIPRegions(this.AdminContext(), &pb.LookupIPRegionsRequest{IpList: ipList})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if resp.IpRegionMap != nil {
|
||||||
|
for ip, region := range resp.IpRegionMap {
|
||||||
|
regionMap[ip] = region.Summary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Data["regions"] = regionMap
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
21
internal/web/actions/default/servers/logs/init.go
Normal file
21
internal/web/actions/default/servers/logs/init.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
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.AdminModuleCodeServer)).
|
||||||
|
Data("teaMenu", "servers").
|
||||||
|
Data("teaSubMenu", "log").
|
||||||
|
Prefix("/servers/logs").
|
||||||
|
Get("", new(IndexAction)).
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -22,6 +22,8 @@ func (this *HistoryAction) RunGet(params struct {
|
|||||||
ServerId int64
|
ServerId int64
|
||||||
Day string
|
Day string
|
||||||
Keyword string
|
Keyword string
|
||||||
|
Ip string
|
||||||
|
Domain string
|
||||||
|
|
||||||
RequestId string
|
RequestId string
|
||||||
HasError int
|
HasError int
|
||||||
@@ -33,6 +35,8 @@ func (this *HistoryAction) RunGet(params struct {
|
|||||||
this.Data["path"] = this.Request.URL.Path
|
this.Data["path"] = this.Request.URL.Path
|
||||||
this.Data["day"] = params.Day
|
this.Data["day"] = params.Day
|
||||||
this.Data["keyword"] = params.Keyword
|
this.Data["keyword"] = params.Keyword
|
||||||
|
this.Data["ip"] = params.Ip
|
||||||
|
this.Data["domain"] = params.Domain
|
||||||
this.Data["accessLogs"] = []interface{}{}
|
this.Data["accessLogs"] = []interface{}{}
|
||||||
this.Data["hasError"] = params.HasError
|
this.Data["hasError"] = params.HasError
|
||||||
|
|
||||||
@@ -51,6 +55,8 @@ func (this *HistoryAction) RunGet(params struct {
|
|||||||
HasError: params.HasError > 0,
|
HasError: params.HasError > 0,
|
||||||
Day: day,
|
Day: day,
|
||||||
Keyword: params.Keyword,
|
Keyword: params.Keyword,
|
||||||
|
Ip: params.Ip,
|
||||||
|
Domain: params.Domain,
|
||||||
Size: size,
|
Size: size,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -84,6 +90,8 @@ func (this *HistoryAction) RunGet(params struct {
|
|||||||
HasError: params.HasError > 0,
|
HasError: params.HasError > 0,
|
||||||
Day: day,
|
Day: day,
|
||||||
Keyword: params.Keyword,
|
Keyword: params.Keyword,
|
||||||
|
Ip: params.Ip,
|
||||||
|
Domain: params.Domain,
|
||||||
Size: size,
|
Size: size,
|
||||||
Reverse: true,
|
Reverse: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -20,10 +20,14 @@ func (this *IndexAction) Init() {
|
|||||||
func (this *IndexAction) RunGet(params struct {
|
func (this *IndexAction) RunGet(params struct {
|
||||||
ServerId int64
|
ServerId int64
|
||||||
RequestId string
|
RequestId string
|
||||||
|
Ip string
|
||||||
|
Domain string
|
||||||
Keyword string
|
Keyword string
|
||||||
}) {
|
}) {
|
||||||
this.Data["serverId"] = params.ServerId
|
this.Data["serverId"] = params.ServerId
|
||||||
this.Data["requestId"] = params.RequestId
|
this.Data["requestId"] = params.RequestId
|
||||||
|
this.Data["ip"] = params.Ip
|
||||||
|
this.Data["domain"] = params.Domain
|
||||||
this.Data["keyword"] = params.Keyword
|
this.Data["keyword"] = params.Keyword
|
||||||
this.Data["path"] = this.Request.URL.Path
|
this.Data["path"] = this.Request.URL.Path
|
||||||
|
|
||||||
@@ -44,6 +48,8 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
ServerId int64
|
ServerId int64
|
||||||
RequestId string
|
RequestId string
|
||||||
Keyword string
|
Keyword string
|
||||||
|
Ip string
|
||||||
|
Domain string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
@@ -54,6 +60,8 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
Size: 20,
|
Size: 20,
|
||||||
Day: timeutil.Format("Ymd"),
|
Day: timeutil.Format("Ymd"),
|
||||||
Keyword: params.Keyword,
|
Keyword: params.Keyword,
|
||||||
|
Ip: params.Ip,
|
||||||
|
Domain: params.Domain,
|
||||||
Reverse: isReverse,
|
Reverse: isReverse,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -21,12 +21,16 @@ func (this *TodayAction) RunGet(params struct {
|
|||||||
ServerId int64
|
ServerId int64
|
||||||
HasError int
|
HasError int
|
||||||
Keyword string
|
Keyword string
|
||||||
|
Ip string
|
||||||
|
Domain string
|
||||||
}) {
|
}) {
|
||||||
size := int64(10)
|
size := int64(10)
|
||||||
|
|
||||||
this.Data["path"] = this.Request.URL.Path
|
this.Data["path"] = this.Request.URL.Path
|
||||||
this.Data["hasError"] = params.HasError
|
this.Data["hasError"] = params.HasError
|
||||||
this.Data["keyword"] = params.Keyword
|
this.Data["keyword"] = params.Keyword
|
||||||
|
this.Data["ip"] = params.Ip
|
||||||
|
this.Data["domain"] = params.Domain
|
||||||
|
|
||||||
resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||||
RequestId: params.RequestId,
|
RequestId: params.RequestId,
|
||||||
@@ -34,6 +38,8 @@ func (this *TodayAction) RunGet(params struct {
|
|||||||
HasError: params.HasError > 0,
|
HasError: params.HasError > 0,
|
||||||
Day: timeutil.Format("Ymd"),
|
Day: timeutil.Format("Ymd"),
|
||||||
Keyword: params.Keyword,
|
Keyword: params.Keyword,
|
||||||
|
Ip: params.Ip,
|
||||||
|
Domain: params.Domain,
|
||||||
Size: size,
|
Size: size,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -67,6 +73,9 @@ func (this *TodayAction) RunGet(params struct {
|
|||||||
ServerId: params.ServerId,
|
ServerId: params.ServerId,
|
||||||
HasError: params.HasError > 0,
|
HasError: params.HasError > 0,
|
||||||
Day: timeutil.Format("Ymd"),
|
Day: timeutil.Format("Ymd"),
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Ip: params.Ip,
|
||||||
|
Domain: params.Domain,
|
||||||
Size: size,
|
Size: size,
|
||||||
Reverse: true,
|
Reverse: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ func (this *SortAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
if webConfig == nil {
|
if webConfig == nil {
|
||||||
this.Success()
|
this.Success()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
refMap := map[int64]*serverconfigs.HTTPLocationRef{}
|
refMap := map[int64]*serverconfigs.HTTPLocationRef{}
|
||||||
for _, ref := range webConfig.LocationRefs {
|
for _, ref := range webConfig.LocationRefs {
|
||||||
|
|||||||
@@ -121,6 +121,10 @@ func (this *SettingAction) RunPost(params struct {
|
|||||||
MaxConns: types.Int32(reverseProxyConfig.MaxConns),
|
MaxConns: types.Int32(reverseProxyConfig.MaxConns),
|
||||||
MaxIdleConns: types.Int32(reverseProxyConfig.MaxIdleConns),
|
MaxIdleConns: types.Int32(reverseProxyConfig.MaxIdleConns),
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,11 +69,12 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) RunPost(params struct {
|
func (this *IndexAction) RunPost(params struct {
|
||||||
Frame string
|
Frame string
|
||||||
CountryIdsJSON []byte
|
CountryIdsJSON []byte
|
||||||
ProvinceIdsJSON []byte
|
ProvinceIdsJSON []byte
|
||||||
AllowLocal bool
|
AllowLocal bool
|
||||||
AllowIPs []string
|
AllowIPs []string
|
||||||
|
AllowRememberLogin bool
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
@@ -127,6 +128,9 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
// 允许本地
|
// 允许本地
|
||||||
config.AllowLocal = params.AllowLocal
|
config.AllowLocal = params.AllowLocal
|
||||||
|
|
||||||
|
// 允许记住登录
|
||||||
|
config.AllowRememberLogin = params.AllowRememberLogin
|
||||||
|
|
||||||
err = configloaders.UpdateSecurityConfig(config)
|
err = configloaders.UpdateSecurityConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -91,12 +91,12 @@ func (this *ValidateDbAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查权限
|
// 检查权限
|
||||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS `edgeTest` ( `id` int )")
|
_, err = db.Exec("CREATE TABLE IF NOT EXISTS `edgeTest` (\n `id` int(11) NOT NULL AUTO_INCREMENT,\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("当前连接的用户无法创建新表,请检查CREATE权限设置:" + err.Error())
|
this.Fail("当前连接的用户无法创建新表,请检查CREATE权限设置:" + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.Exec("ALTER TABLE `edgeTest` CHANGE `id` `id` int")
|
_, err = db.Exec("ALTER TABLE `edgeTest` CHANGE `id` `id` int(11) NOT NULL AUTO_INCREMENT")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("当前连接的用户无法修改表结构,请检查ALTER权限设置:" + err.Error())
|
this.Fail("当前连接的用户无法修改表结构,请检查ALTER权限设置:" + err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -63,6 +64,11 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
|
|||||||
action.ResponseWriter.WriteHeader(http.StatusForbidden)
|
action.ResponseWriter.WriteHeader(http.StatusForbidden)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
remoteAddr, _, _ := net.SplitHostPort(action.Request.RemoteAddr)
|
||||||
|
if len(remoteAddr) > 0 && remoteAddr != action.RequestRemoteIP() && !checkIP(securityConfig, remoteAddr) {
|
||||||
|
action.ResponseWriter.WriteHeader(http.StatusForbidden)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// 检查系统是否已经配置过
|
// 检查系统是否已经配置过
|
||||||
if !setup.IsConfigured() {
|
if !setup.IsConfigured() {
|
||||||
@@ -174,6 +180,11 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
|||||||
"subtitle": "服务列表",
|
"subtitle": "服务列表",
|
||||||
"icon": "clone outsize",
|
"icon": "clone outsize",
|
||||||
"subItems": []maps.Map{
|
"subItems": []maps.Map{
|
||||||
|
{
|
||||||
|
"name": "访问日志",
|
||||||
|
"url": "/servers/logs",
|
||||||
|
"code": "log",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "通用设置",
|
"name": "通用设置",
|
||||||
"url": "/servers/components",
|
"url": "/servers/components",
|
||||||
@@ -261,13 +272,17 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "ns",
|
"code": "ns",
|
||||||
"module": configloaders.AdminModuleCodeNS,
|
"module": configloaders.AdminModuleCodeNS,
|
||||||
"name": "自建DNS",
|
"name": "自建DNS",
|
||||||
"subtitle": "域名列表",
|
"icon": "cubes",
|
||||||
"icon": "cubes",
|
"isOn": teaconst.IsPlus,
|
||||||
"isOn": teaconst.IsPlus,
|
|
||||||
"subItems": []maps.Map{
|
"subItems": []maps.Map{
|
||||||
|
{
|
||||||
|
"name": "域名管理",
|
||||||
|
"url": "/ns/domains",
|
||||||
|
"code": "domain",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "集群管理",
|
"name": "集群管理",
|
||||||
"url": "/ns/clusters",
|
"url": "/ns/clusters",
|
||||||
@@ -288,6 +303,16 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
|||||||
"url": "/ns/clusters/logs",
|
"url": "/ns/clusters/logs",
|
||||||
"code": "log",
|
"code": "log",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "全局配置",
|
||||||
|
"url": "/ns/settings",
|
||||||
|
"code": "setting",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "解析测试",
|
||||||
|
"url": "/ns/test",
|
||||||
|
"code": "test",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,6 +36,11 @@ func (this *UserShouldAuth) BeforeAction(actionPtr actions.ActionWrapper, paramN
|
|||||||
action.ResponseWriter.WriteHeader(http.StatusForbidden)
|
action.ResponseWriter.WriteHeader(http.StatusForbidden)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
remoteAddr, _, _ := net.SplitHostPort(action.Request.RemoteAddr)
|
||||||
|
if len(remoteAddr) > 0 && remoteAddr != action.RequestRemoteIP() && !checkIP(securityConfig, remoteAddr) {
|
||||||
|
action.ResponseWriter.WriteHeader(http.StatusForbidden)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ import (
|
|||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/cluster/settings/accessLog"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/cluster/settings/accessLog"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/logs"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/logs"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/routes"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/routes"
|
||||||
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/settings/accesslogs"
|
||||||
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/test"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/users"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/users"
|
||||||
|
|
||||||
// 服务相关
|
// 服务相关
|
||||||
@@ -61,6 +63,7 @@ import (
|
|||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/groups"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/groups"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/log"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/log"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/waf"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/waf"
|
||||||
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/logs"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/metrics"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/metrics"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/metrics/charts"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/metrics/charts"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Vue.component("copy-to-clipboard", {
|
|||||||
methods: {
|
methods: {
|
||||||
copy: function () {
|
copy: function () {
|
||||||
new ClipboardJS('[data-clipboard-target]');
|
new ClipboardJS('[data-clipboard-target]');
|
||||||
teaweb.success("已复制到剪切板")
|
teaweb.successToast("已复制到剪切板")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<a href="" title="拷贝到剪切板" :data-clipboard-target="'#' + vTarget" @click.prevent="copy"><i class="ui icon copy small"></i></em></a>`
|
template: `<a href="" title="拷贝到剪切板" :data-clipboard-target="'#' + vTarget" @click.prevent="copy"><i class="ui icon copy small"></i></em></a>`
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ Vue.component("dns-route-selector", {
|
|||||||
this.isAdding = false
|
this.isAdding = false
|
||||||
},
|
},
|
||||||
remove: function (route) {
|
remove: function (route) {
|
||||||
this.routeCodes.$removeValue(route.code)
|
this.routeCodes.$removeValue(route.code + "@" + route.domainId)
|
||||||
this.routes.$removeIf(function (k, v) {
|
this.routes.$removeIf(function (k, v) {
|
||||||
return v.code == route.code
|
return v.code + "@" + v.domainId == route.code + "@" + route.domainId
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,36 +1,42 @@
|
|||||||
Vue.component("grant-selector", {
|
Vue.component("grant-selector", {
|
||||||
props: ["vGrant"],
|
props: ["v-grant", "v-node-cluster-id", "v-ns-cluster-id"],
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
grantId: (this.vGrant == null) ? 0 : this.vGrant.id,
|
grantId: (this.vGrant == null) ? 0 : this.vGrant.id,
|
||||||
grant: this.vGrant
|
grant: this.vGrant,
|
||||||
|
nodeClusterId: (this.vNodeClusterId != null) ? this.vNodeClusterId : 0,
|
||||||
|
nsClusterId: (this.vNsClusterId != null) ? this.vNsClusterId : 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 选择授权
|
// 选择授权
|
||||||
select: function () {
|
select: function () {
|
||||||
let that = this;
|
let that = this;
|
||||||
teaweb.popup("/clusters/grants/selectPopup", {
|
teaweb.popup("/clusters/grants/selectPopup?nodeClusterId=" + this.nodeClusterId + "&nsClusterId=" + this.nsClusterId, {
|
||||||
callback: (resp) => {
|
callback: (resp) => {
|
||||||
that.grantId = resp.data.grant.id;
|
that.grantId = resp.data.grant.id;
|
||||||
if (that.grantId > 0) {
|
if (that.grantId > 0) {
|
||||||
that.grant = resp.data.grant;
|
that.grant = resp.data.grant;
|
||||||
}
|
}
|
||||||
}
|
that.notifyUpdate()
|
||||||
});
|
},
|
||||||
|
height: "26em"
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// 创建授权
|
// 创建授权
|
||||||
create: function () {
|
create: function () {
|
||||||
|
let that = this
|
||||||
teaweb.popup("/clusters/grants/createPopup", {
|
teaweb.popup("/clusters/grants/createPopup", {
|
||||||
height: "26em",
|
height: "26em",
|
||||||
callback: (resp) => {
|
callback: (resp) => {
|
||||||
this.grantId = resp.data.grant.id;
|
that.grantId = resp.data.grant.id;
|
||||||
if (this.grantId > 0) {
|
if (that.grantId > 0) {
|
||||||
this.grant = resp.data.grant;
|
that.grant = resp.data.grant;
|
||||||
}
|
}
|
||||||
|
that.notifyUpdate()
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// 修改授权
|
// 修改授权
|
||||||
@@ -39,23 +45,29 @@ Vue.component("grant-selector", {
|
|||||||
window.location.reload();
|
window.location.reload();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let that = this
|
||||||
teaweb.popup("/clusters/grants/updatePopup?grantId=" + this.grant.id, {
|
teaweb.popup("/clusters/grants/updatePopup?grantId=" + this.grant.id, {
|
||||||
height: "26em",
|
height: "26em",
|
||||||
callback: (resp) => {
|
callback: (resp) => {
|
||||||
this.grant = resp.data.grant;
|
that.grant = resp.data.grant
|
||||||
|
that.notifyUpdate()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// 删除已选择授权
|
// 删除已选择授权
|
||||||
remove: function () {
|
remove: function () {
|
||||||
this.grant = null;
|
this.grant = null
|
||||||
this.grantId = 0;
|
this.grantId = 0
|
||||||
|
this.notifyUpdate()
|
||||||
|
},
|
||||||
|
notifyUpdate: function () {
|
||||||
|
this.$emit("change", this.grant)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="grantId" :value="grantId"/>
|
<input type="hidden" name="grantId" :value="grantId"/>
|
||||||
<div class="ui label small basic" v-if="grant != null">{{grant.name}}<span class="small">({{grant.methodName}})</span> <a href="" title="修改" @click.prevent="update()"><i class="icon pencil small"></i></a> <a href="" title="删除" @click.prevent="remove()"><i class="icon remove"></i></a> </div>
|
<div class="ui label small basic" v-if="grant != null">{{grant.name}}<span class="small grey">({{grant.methodName}})</span><span class="small grey" v-if="grant.username != null && grant.username.length > 0">({{grant.username}})</span> <a href="" title="修改" @click.prevent="update()"><i class="icon pencil small"></i></a> <a href="" title="删除" @click.prevent="remove()"><i class="icon remove"></i></a> </div>
|
||||||
<div v-if="grant == null">
|
<div v-if="grant == null">
|
||||||
<a href="" @click.prevent="select()">[选择已有认证]</a> <a href="" @click.prevent="create()">[添加新认证]</a>
|
<a href="" @click.prevent="select()">[选择已有认证]</a> <a href="" @click.prevent="create()">[添加新认证]</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -41,11 +41,13 @@ Vue.component("message-row", {
|
|||||||
<strong>{{message.datetime}}</strong>
|
<strong>{{message.datetime}}</strong>
|
||||||
<span v-if="message.cluster != null && message.cluster.id != null">
|
<span v-if="message.cluster != null && message.cluster.id != null">
|
||||||
<span> | </span>
|
<span> | </span>
|
||||||
<a :href="'/clusters/cluster?clusterId=' + message.cluster.id" target="_top">集群:{{message.cluster.name}}</a>
|
<a :href="'/clusters/cluster?clusterId=' + message.cluster.id" target="_top" v-if="message.role == 'node'">集群:{{message.cluster.name}}</a>
|
||||||
|
<a :href="'/ns/clusters/cluster?clusterId=' + message.cluster.id" target="_top" v-if="message.role == 'dns'">DNS集群:{{message.cluster.name}}</a>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="message.node != null && message.node.id != null">
|
<span v-if="message.node != null && message.node.id != null">
|
||||||
<span> | </span>
|
<span> | </span>
|
||||||
<a :href="'/clusters/cluster/node?clusterId=' + message.cluster.id + '&nodeId=' + message.node.id" target="_top">节点:{{message.node.name}}</a>
|
<a :href="'/clusters/cluster/node?clusterId=' + message.cluster.id + '&nodeId=' + message.node.id" target="_top" v-if="message.role == 'node'">节点:{{message.node.name}}</a>
|
||||||
|
<a :href="'/ns/clusters/cluster/node?clusterId=' + message.cluster.id + '&nodeId=' + message.node.id" target="_top" v-if="message.role == 'dns'">DNS节点:{{message.node.name}}</a>
|
||||||
</span>
|
</span>
|
||||||
<a href="" style="position: absolute; right: 1em" @click.prevent="readMessage(message.id)" title="标为已读"><i class="icon check"></i></a>
|
<a href="" style="position: absolute; right: 1em" @click.prevent="readMessage(message.id)" title="标为已读"><i class="icon check"></i></a>
|
||||||
</td>
|
</td>
|
||||||
@@ -73,6 +75,8 @@ Vue.component("message-row", {
|
|||||||
<div v-if="message.type == 'SSLCertACMETaskSuccess'" style="margin-top: 0.8em">
|
<div v-if="message.type == 'SSLCertACMETaskSuccess'" style="margin-top: 0.8em">
|
||||||
<a href="" @click.prevent="viewCert(params.certId)" target="_top">查看证书</a> | <a :href="'/servers/certs/acme'" v-if="params != null && params.acmeTaskId > 0" target="_top">查看任务»</a>
|
<a href="" @click.prevent="viewCert(params.certId)" target="_top">查看证书</a> | <a :href="'/servers/certs/acme'" v-if="params != null && params.acmeTaskId > 0" target="_top">查看任务»</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 证书续期失败 -->
|
||||||
<div v-if="message.type == 'SSLCertACMETaskFailed'" style="margin-top: 0.8em">
|
<div v-if="message.type == 'SSLCertACMETaskFailed'" style="margin-top: 0.8em">
|
||||||
<a href="" @click.prevent="viewCert(params.certId)" target="_top">查看证书</a> | <a :href="'/servers/certs/acme'" v-if="params != null && params.acmeTaskId > 0" target="_top">查看任务»</a>
|
<a href="" @click.prevent="viewCert(params.certId)" target="_top">查看证书</a> | <a :href="'/servers/certs/acme'" v-if="params != null && params.acmeTaskId > 0" target="_top">查看任务»</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
60
web/public/js/components/node/node-login-suggest-ports.js
Normal file
60
web/public/js/components/node/node-login-suggest-ports.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// 节点登录推荐端口
|
||||||
|
Vue.component("node-login-suggest-ports", {
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
ports: [],
|
||||||
|
availablePorts: [],
|
||||||
|
autoSelected: false,
|
||||||
|
isLoading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
reload: function (host) {
|
||||||
|
let that = this
|
||||||
|
this.autoSelected = false
|
||||||
|
this.isLoading = true
|
||||||
|
Tea.action("/clusters/cluster/suggestLoginPorts")
|
||||||
|
.params({
|
||||||
|
host: host
|
||||||
|
})
|
||||||
|
.success(function (resp) {
|
||||||
|
if (resp.data.availablePorts != null) {
|
||||||
|
that.availablePorts = resp.data.availablePorts
|
||||||
|
if (that.availablePorts.length > 0) {
|
||||||
|
that.autoSelectPort(that.availablePorts[0])
|
||||||
|
that.autoSelected = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resp.data.ports != null) {
|
||||||
|
that.ports = resp.data.ports
|
||||||
|
if (that.ports.length > 0 && !that.autoSelected) {
|
||||||
|
that.autoSelectPort(that.ports[0])
|
||||||
|
that.autoSelected = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.done(function () {
|
||||||
|
that.isLoading = false
|
||||||
|
})
|
||||||
|
.post()
|
||||||
|
},
|
||||||
|
selectPort: function (port) {
|
||||||
|
this.$emit("select", port)
|
||||||
|
},
|
||||||
|
autoSelectPort: function (port) {
|
||||||
|
this.$emit("auto-select", port)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<span>
|
||||||
|
<span v-if="isLoading">正在检查端口...</span>
|
||||||
|
<span v-if="availablePorts.length > 0">
|
||||||
|
可能端口:<a href="" v-for="port in availablePorts" @click.prevent="selectPort(port)" class="ui label tiny basic blue" style="border: 1px #2185d0 dashed; font-weight: normal">{{port}}</a>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
<span v-if="ports.length > 0">
|
||||||
|
常用端口:<a href="" v-for="port in ports" @click.prevent="selectPort(port)" class="ui label tiny basic blue" style="border: 1px #2185d0 dashed; font-weight: normal">{{port}}</a>
|
||||||
|
</span>
|
||||||
|
<span v-if="ports.length == 0">常用端口有22等。</span>
|
||||||
|
<span v-if="ports.length > 0" class="grey small">(可以点击要使用的端口)</span>
|
||||||
|
</span>`
|
||||||
|
})
|
||||||
@@ -1,13 +1,17 @@
|
|||||||
Vue.component("ns-access-log-ref-box", {
|
Vue.component("ns-access-log-ref-box", {
|
||||||
props:["v-access-log-ref"],
|
props: ["v-access-log-ref", "v-is-parent"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let config = this.vAccessLogRef
|
let config = this.vAccessLogRef
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
config = {
|
config = {
|
||||||
isOn: false,
|
isOn: false,
|
||||||
isPrior: false
|
isPrior: false,
|
||||||
|
logMissingDomains: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (typeof (config.logMissingDomains) == "undefined") {
|
||||||
|
config.logMissingDomains = false
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
config: config
|
config: config
|
||||||
}
|
}
|
||||||
@@ -15,12 +19,22 @@ Vue.component("ns-access-log-ref-box", {
|
|||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="accessLogJSON" :value="JSON.stringify(config)"/>
|
<input type="hidden" name="accessLogJSON" :value="JSON.stringify(config)"/>
|
||||||
<table class="ui table definition selectable">
|
<table class="ui table definition selectable">
|
||||||
<tr>
|
<prior-checkbox :v-config="config" v-if="!vIsParent"></prior-checkbox>
|
||||||
<td class="title">是否启用</td>
|
<tbody v-show="vIsParent || config.isPrior">
|
||||||
<td>
|
<tr>
|
||||||
<checkbox name="isOn" value="1" v-model="config.isOn"></checkbox>
|
<td class="title">是否启用</td>
|
||||||
</td>
|
<td>
|
||||||
</tr>
|
<checkbox name="isOn" value="1" v-model="config.isOn"></checkbox>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>记录所有访问</td>
|
||||||
|
<td>
|
||||||
|
<checkbox name="logMissingDomains" value="1" v-model="config.logMissingDomains"></checkbox>
|
||||||
|
<p class="comment">包括对没有在系统里创建的域名访问。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="margin"></div>
|
<div class="margin"></div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// 选择单一线路
|
// 选择单一线路
|
||||||
Vue.component("ns-route-selector", {
|
Vue.component("ns-route-selector", {
|
||||||
props: ["v-route-id"],
|
props: ["v-route-code"],
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
let that = this
|
let that = this
|
||||||
Tea.action("/ns/routes/options")
|
Tea.action("/ns/routes/options")
|
||||||
@@ -10,20 +10,20 @@ Vue.component("ns-route-selector", {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
let routeId = this.vRouteId
|
let routeCode = this.vRouteCode
|
||||||
if (routeId == null) {
|
if (routeCode == null) {
|
||||||
routeId = 0
|
routeCode = ""
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
routeId: routeId,
|
routeCode: routeCode,
|
||||||
routes: []
|
routes: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<div v-if="routes.length > 0">
|
<div v-if="routes.length > 0">
|
||||||
<select class="ui dropdown" name="routeId" v-model="routeId">
|
<select class="ui dropdown" name="routeCode" v-model="routeCode">
|
||||||
<option value="0">[线路]</option>
|
<option value="">[线路]</option>
|
||||||
<option v-for="route in routes" :value="route.id">{{route.name}}</option>
|
<option v-for="route in routes" :value="route.code">{{route.name}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|||||||
@@ -1,66 +1,70 @@
|
|||||||
// 选择多个线路
|
// 选择多个线路
|
||||||
Vue.component("ns-routes-selector", {
|
Vue.component("ns-routes-selector", {
|
||||||
props: ["v-route-ids"],
|
props: ["v-routes"],
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
let that = this
|
let that = this
|
||||||
|
|
||||||
let routeIds = this.vRouteIds
|
|
||||||
if (routeIds == null) {
|
|
||||||
routeIds = []
|
|
||||||
}
|
|
||||||
|
|
||||||
Tea.action("/ns/routes/options")
|
Tea.action("/ns/routes/options")
|
||||||
.post()
|
.post()
|
||||||
.success(function (resp) {
|
.success(function (resp) {
|
||||||
that.allRoutes = resp.data.routes
|
that.routes = resp.data.routes
|
||||||
that.allRoutes.forEach(function (v) {
|
|
||||||
v.isChecked = (routeIds.$contains(v.id))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
let selectedRoutes = this.vRoutes
|
||||||
routeId: 0,
|
if (selectedRoutes == null) {
|
||||||
allRoutes: [],
|
selectedRoutes = []
|
||||||
routes: [],
|
|
||||||
isAdding: false
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
,
|
return {
|
||||||
|
routeCode: "default",
|
||||||
|
routes: [],
|
||||||
|
isAdding: false,
|
||||||
|
routeType: "default",
|
||||||
|
selectedRoutes: selectedRoutes
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
routeType: function (v) {
|
||||||
|
this.routeCode = ""
|
||||||
|
let that = this
|
||||||
|
this.routes.forEach(function (route) {
|
||||||
|
if (route.type == v && that.routeCode.length == 0) {
|
||||||
|
that.routeCode = route.code
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
add: function () {
|
add: function () {
|
||||||
this.isAdding = true
|
this.isAdding = true
|
||||||
this.routes = this.allRoutes.$findAll(function (k, v) {
|
this.routeType = "default"
|
||||||
return !v.isChecked
|
this.routeCode = "default"
|
||||||
})
|
|
||||||
this.routeId = 0
|
|
||||||
},
|
},
|
||||||
cancel: function () {
|
cancel: function () {
|
||||||
this.isAdding = false
|
this.isAdding = false
|
||||||
},
|
},
|
||||||
confirm: function () {
|
confirm: function () {
|
||||||
if (this.routeId == 0) {
|
if (this.routeCode.length == 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let that = this
|
let that = this
|
||||||
this.routes.forEach(function (v) {
|
this.routes.forEach(function (v) {
|
||||||
if (v.id == that.routeId) {
|
if (v.code == that.routeCode) {
|
||||||
v.isChecked = true
|
that.selectedRoutes.push(v)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.cancel()
|
this.cancel()
|
||||||
},
|
},
|
||||||
remove: function (index) {
|
remove: function (index) {
|
||||||
this.allRoutes[index].isChecked = false
|
this.selectedRoutes.$remove(index)
|
||||||
Vue.set(this.allRoutes, index, this.allRoutes[index])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<div>
|
<div>
|
||||||
<div class="ui label basic text small" v-for="(route, index) in allRoutes" v-if="route.isChecked">
|
<div class="ui label basic text small" v-for="(route, index) in selectedRoutes" style="margin-bottom: 0.3em">
|
||||||
<input type="hidden" name="routeIds" :value="route.id"/>
|
<input type="hidden" name="routeCodes" :value="route.code"/>
|
||||||
{{route.name}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
{{route.name}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
@@ -68,11 +72,21 @@ Vue.component("ns-routes-selector", {
|
|||||||
<div v-if="isAdding" style="margin-bottom: 1em">
|
<div v-if="isAdding" style="margin-bottom: 1em">
|
||||||
<div class="ui fields inline">
|
<div class="ui fields inline">
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<select class="ui dropdown" name="routeId" v-model="routeId">
|
<select class="ui dropdown" v-model="routeType">
|
||||||
<option value="0">[线路]</option>
|
<option value="default">[默认线路]</option>
|
||||||
<option v-for="route in routes" :value="route.id">{{route.name}}</option>
|
<option value="user">自定义线路</option>
|
||||||
|
<option value="isp">运营商</option>
|
||||||
|
<option value="china">中国省市</option>
|
||||||
|
<option value="world">全球国家地区</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="ui field">
|
||||||
|
<select class="ui dropdown" v-model="routeCode" style="width: 10em">
|
||||||
|
<option v-for="route in routes" :value="route.code" v-if="route.type == routeType">{{route.name}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<button type="button" class="ui button tiny" @click.prevent="confirm">确定</button>
|
<button type="button" class="ui button tiny" @click.prevent="confirm">确定</button>
|
||||||
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ Vue.component("http-access-log-box", {
|
|||||||
this.$refs.box.parentNode.style.cssText = ""
|
this.$refs.box.parentNode.style.cssText = ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div :style="{'color': (accessLog.status >= 400) ? '#dc143c' : ''}" ref="box">
|
template: `<div style="word-break: break-all" :style="{'color': (accessLog.status >= 400) ? '#dc143c' : ''}" ref="box">
|
||||||
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <ip-box><keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword></ip-box> [{{accessLog.timeLocal}}] <em>"<keyword :v-word="vKeyword">{{accessLog.requestMethod}}</keyword> {{accessLog.scheme}}://<keyword :v-word="vKeyword">{{accessLog.host}}</keyword><keyword :v-word="vKeyword">{{accessLog.requestURI}}</keyword> <a :href="accessLog.scheme + '://' + accessLog.host + accessLog.requestURI" target="_blank" title="新窗口打开" class="disabled"><i class="external icon tiny"></i> </a> {{accessLog.proto}}" </em> <keyword :v-word="vKeyword">{{accessLog.status}}</keyword> <code-label v-if="accessLog.attrs != null && accessLog.attrs['cache.status'] == 'HIT'">cache hit</code-label> <code-label v-if="accessLog.firewallActions != null && accessLog.firewallActions.length > 0">waf {{accessLog.firewallActions}}</code-label> <span v-if="accessLog.tags != null && accessLog.tags.length > 0">- <code-label v-for="tag in accessLog.tags">{{tag}}</code-label></span> - 耗时:{{formatCost(accessLog.requestTime)}} ms <span v-if="accessLog.humanTime != null && accessLog.humanTime.length > 0" class="grey small"> ({{accessLog.humanTime}})</span>
|
<a v-if="accessLog.node != null && accessLog.node.nodeCluster != null" :href="'/clusters/cluster/node?nodeId=' + accessLog.node.id + '&clusterId=' + accessLog.node.nodeCluster.id" title="点击查看节点详情" target="_top"><span class="grey">[{{accessLog.node.name}}<span v-if="!accessLog.node.name.endsWith('节点')">节点</span>]</span></a><span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <ip-box><keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword></ip-box> [{{accessLog.timeLocal}}] <em>"<keyword :v-word="vKeyword">{{accessLog.requestMethod}}</keyword> {{accessLog.scheme}}://<keyword :v-word="vKeyword">{{accessLog.host}}</keyword><keyword :v-word="vKeyword">{{accessLog.requestURI}}</keyword> <a :href="accessLog.scheme + '://' + accessLog.host + accessLog.requestURI" target="_blank" title="新窗口打开" class="disabled"><i class="external icon tiny"></i> </a> {{accessLog.proto}}" </em> <keyword :v-word="vKeyword">{{accessLog.status}}</keyword> <code-label v-if="accessLog.attrs != null && accessLog.attrs['cache.status'] == 'HIT'">cache hit</code-label> <code-label v-if="accessLog.firewallActions != null && accessLog.firewallActions.length > 0">waf {{accessLog.firewallActions}}</code-label> <span v-if="accessLog.tags != null && accessLog.tags.length > 0">- <code-label v-for="tag in accessLog.tags">{{tag}}</code-label></span> - 耗时:{{formatCost(accessLog.requestTime)}} ms <span v-if="accessLog.humanTime != null && accessLog.humanTime.length > 0" class="grey small"> ({{accessLog.humanTime}})</span>
|
||||||
<a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>
|
<a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// 访问日志搜索框
|
||||||
|
Vue.component("http-access-log-search-box", {
|
||||||
|
props: ["v-ip", "v-domain", "v-keyword"],
|
||||||
|
data: function () {
|
||||||
|
let ip = this.vIp
|
||||||
|
if (ip == null) {
|
||||||
|
ip = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
let domain = this.vDomain
|
||||||
|
if (domain == null) {
|
||||||
|
domain = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
let keyword = this.vKeyword
|
||||||
|
if (keyword == null) {
|
||||||
|
keyword = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
ip: ip,
|
||||||
|
domain: domain,
|
||||||
|
keyword: keyword
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<div class="margin"></div>
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<div class="ui input left labeled small">
|
||||||
|
<span class="ui label basic" style="font-weight: normal">IP</span>
|
||||||
|
<input type="text" name="ip" placeholder="x.x.x.x" size="15" v-model="ip"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<div class="ui input left labeled small">
|
||||||
|
<span class="ui label basic" style="font-weight: normal">域名</span>
|
||||||
|
<input type="text" name="domain" placeholder="xxx.com" size="15" v-model="domain"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<div class="ui input left labeled small">
|
||||||
|
<span class="ui label basic" style="font-weight: normal">关键词</span>
|
||||||
|
<input type="text" name="keyword" v-model="keyword" placeholder="路径、UserAgent等..." size="18"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<slot></slot>
|
||||||
|
<div class="ui field">
|
||||||
|
<button class="ui button small" type="submit">查找</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
20
web/public/js/world.js
Normal file
20
web/public/js/world.js
Normal file
File diff suppressed because one or more lines are too long
@@ -4,4 +4,10 @@
|
|||||||
.right-box {
|
.right-box {
|
||||||
top: 10em;
|
top: 10em;
|
||||||
}
|
}
|
||||||
|
.row {
|
||||||
|
line-height: 4;
|
||||||
|
}
|
||||||
|
.step.active {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
/*# sourceMappingURL=createNode.css.map */
|
/*# sourceMappingURL=createNode.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["createNode.less"],"names":[],"mappings":"AAAA;EACC,SAAA;;AAGD;EACC,SAAA","file":"createNode.css"}
|
{"version":3,"sources":["createNode.less"],"names":[],"mappings":"AAAA;EACC,SAAA;;AAGD;EACC,SAAA;;AAGD;EACC,cAAA;;AAGD,KAAK;EACJ,iBAAA","file":"createNode.css"}
|
||||||
@@ -1,9 +1,23 @@
|
|||||||
{$layout}
|
{$layout}
|
||||||
{$template "/clusters/cluster/menu"}
|
{$template "/clusters/cluster/menu"}
|
||||||
{$template "/left_menu"}
|
{$template "/left_menu"}
|
||||||
|
{$template "/code_editor"}
|
||||||
|
|
||||||
<div class="right-box">
|
<div class="right-box">
|
||||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
<div class="ui steps small fluid">
|
||||||
|
<div class="ui step" :class="{active: step == 'info'}">
|
||||||
|
<div class="content">1. 填写节点信息</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui step" :class="{active: step == 'install'}">
|
||||||
|
<div class="content">2. 安装节点</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui step" :class="{active: step == 'finish'}">
|
||||||
|
<div class="content">3. 完成</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 填写信息 -->
|
||||||
|
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success" v-show="step == 'info'">
|
||||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||||
<table class="ui table definition selectable">
|
<table class="ui table definition selectable">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -51,7 +65,7 @@
|
|||||||
<td>SSH主机地址</td>
|
<td>SSH主机地址</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="sshHost" maxlength="64"/>
|
<input type="text" name="sshHost" maxlength="64"/>
|
||||||
<p class="comment">比如192.168.1.100</p>
|
<p class="comment">比如192.168.1.100,用于远程安装节点应用程序。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -64,11 +78,93 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>SSH登录认证</td>
|
<td>SSH登录认证</td>
|
||||||
<td>
|
<td>
|
||||||
<grant-selector></grant-selector>
|
<grant-selector :v-node-cluster-id="clusterId"></grant-selector>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<submit-btn></submit-btn>
|
<submit-btn>下一步</submit-btn>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<!-- 安装节点 -->
|
||||||
|
<div v-if="step == 'install'">
|
||||||
|
<div class="ui tabular menu">
|
||||||
|
<a href="" class="item" :class="{active: installMethod == 'remote'}" @click.prevent="switchInstallMethod('remote')">远程安装</a>
|
||||||
|
<a href="" class="item" :class="{active: installMethod == 'manual'}" @click.prevent="switchInstallMethod('manual')">手动安装</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 远程安装 -->
|
||||||
|
<div v-if="installMethod == 'remote'">
|
||||||
|
<form class="ui form">
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">SSH主机地址 *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="sshHost2" maxlength="64" v-model="sshHost" ref="installSSHHostRef" style="width: 16em" @change="changeSSHHost"/>
|
||||||
|
<div v-if="node.addresses != null && node.addresses.length > 1" style="margin-top: 1em">
|
||||||
|
<a href="" class="ui label small basic" v-for="addr in node.addresses" title="点击使用" @click.prevent="selectSSHHost(addr)">{{addr}}</a>
|
||||||
|
</div>
|
||||||
|
<p class="comment">比如192.168.1.100,用于远程安装节点应用程序。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SSH主机端口 *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="sshPort2" maxlength="5" v-model="sshPort" style="width:5em"/>
|
||||||
|
<p class="comment"><node-login-suggest-ports ref="nodeLoginSuggestPortsRef" @select="selectLoginPort" @auto-select="autoSelectLoginPort"></node-login-suggest-ports></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SSH登录认证 *</td>
|
||||||
|
<td>
|
||||||
|
<grant-selector :v-grant="node.grant" :v-node-cluster-id="clusterId" @change="changeGrant"></grant-selector>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<div v-if="installStatus != null && (installStatus.isRunning || installStatus.isFinished)"
|
||||||
|
class="ui segment installing-box">
|
||||||
|
<div v-if="installStatus.isRunning" class="blue">安装中...</div>
|
||||||
|
<div v-if="installStatus.isFinished">
|
||||||
|
<span v-if="installStatus.isOk" class="green">已安装成功</span>
|
||||||
|
<span v-if="!installStatus.isOk" class="red">安装过程中发生错误:{{installStatus.error}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="ui primary button" type="button" @click.prevent="install" v-if="!isInstalling">远程安装</button>
|
||||||
|
<button class="ui button disabled" v-if="isInstalling">正在安装</button>
|
||||||
|
<a href="" @click.prevent="finish" v-if="!isInstalling" style="margin-left: 1em; float: right">跳过安装</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 手动安装 -->
|
||||||
|
<div v-if="installMethod == 'manual'">
|
||||||
|
<div class="row">在边缘节点安装目录下,复制<code-label>configs/api.template.yaml</code-label>为<code-label>configs/api.yaml</code-label>,然后修改文件里面的内容为以下内容:</div>
|
||||||
|
<source-code-box id="rpc-code" type="text/yaml">rpc:
|
||||||
|
endpoints: [ {{apiEndpoints}} ]
|
||||||
|
nodeId: "{{node.uniqueId}}"
|
||||||
|
secret: "{{node.secret}}"</source-code-box>
|
||||||
|
<div class="row">然后再使用<code-label>bin/edge-node start</code-label>命令启动节点。</div>
|
||||||
|
<div>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<a href="" @click.prevent="finish">安装完成</a>
|
||||||
|
<a href="" @click.prevent="finish" style="float: right">跳过安装</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 完成 -->
|
||||||
|
<div v-show="step == 'finish'">
|
||||||
|
<div>
|
||||||
|
<div style="text-align: center; font-size: 1.4em; margin-top: 2.4em" v-if="isInstalled"><span class="green">"{{node.name}}"节点已被创建并安装成功。</span></div>
|
||||||
|
<div style="text-align: center; font-size: 1.4em; margin-top: 2.4em" v-if="!isInstalled"><span class="green">"{{node.name}}"节点已创建成功。</span></div>
|
||||||
|
<div style="text-align: center; margin-top: 3em">
|
||||||
|
<a :href="'/clusters/cluster/node?nodeId=' + nodeId + '&clusterId=' + clusterId" class="ui button primary" type="button">现在进入节点详情<i class="ui icon long arrow alternate right"></i></a>
|
||||||
|
</div>
|
||||||
|
<div style="text-align: center; margin-top: 1em">
|
||||||
|
<a href="" @click.prevent="createNext">继续创建下一个节点</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,3 +1,173 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.success = NotifySuccess("保存成功", "/clusters/cluster/nodes?clusterId=" + this.clusterId);
|
this.nodeId = 0
|
||||||
});
|
this.node = {}
|
||||||
|
this.sshHost = ""
|
||||||
|
this.sshPort = ""
|
||||||
|
this.grantId = 0
|
||||||
|
this.step = "info"
|
||||||
|
|
||||||
|
this.success = function (resp) {
|
||||||
|
this.node = resp.data.node
|
||||||
|
this.nodeId = this.node.id
|
||||||
|
this.sshHost = this.node.login.params.host
|
||||||
|
if (this.node.login.params.port > 0) {
|
||||||
|
this.sshPort = this.node.login.params.port
|
||||||
|
}
|
||||||
|
if (this.node.addresses.length > 0) {
|
||||||
|
this.sshHost = this.node.addresses[0]
|
||||||
|
}
|
||||||
|
this.step = "install"
|
||||||
|
this.$delay(function () {
|
||||||
|
this.$refs.installSSHHostRef.focus()
|
||||||
|
this.$refs.nodeLoginSuggestPortsRef.reload(this.sshHost)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安装
|
||||||
|
*/
|
||||||
|
this.isInstalled = false
|
||||||
|
this.installMethod = "remote" // remote | manual
|
||||||
|
this.isInstalling = false
|
||||||
|
|
||||||
|
this.switchInstallMethod = function (method) {
|
||||||
|
this.installMethod = method
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectSSHHost = function (host) {
|
||||||
|
this.sshHost = host
|
||||||
|
this.changeSSHHost()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.changeSSHHost = function () {
|
||||||
|
if (this.$refs.nodeLoginSuggestPortsRef != null) {
|
||||||
|
this.$refs.nodeLoginSuggestPortsRef.reload(this.sshHost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectLoginPort = function (port) {
|
||||||
|
this.sshPort = port
|
||||||
|
}
|
||||||
|
|
||||||
|
this.autoSelectLoginPort = function (port) {
|
||||||
|
if (this.sshPort == null || this.sshPort <= 0) {
|
||||||
|
this.sshPort = port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.install = function () {
|
||||||
|
if (this.node.grant != null) {
|
||||||
|
this.grantId = this.node.grant.id
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isInstalling = true
|
||||||
|
this.$post(".createNodeInstall")
|
||||||
|
.params({
|
||||||
|
nodeId: this.node.id,
|
||||||
|
sshHost: this.sshHost,
|
||||||
|
sshPort: this.sshPort,
|
||||||
|
grantId: this.grantId
|
||||||
|
})
|
||||||
|
.timeout(30)
|
||||||
|
.success(function () {
|
||||||
|
this.$delay(function () {
|
||||||
|
this.isInstalling = true
|
||||||
|
this.reloadStatus(this.node.id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.done(function () {
|
||||||
|
this.isInstalling = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.changeGrant = function (grant) {
|
||||||
|
if (grant != null) {
|
||||||
|
this.grantId = grant.id
|
||||||
|
} else {
|
||||||
|
this.grantId = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新状态
|
||||||
|
this.installStatus = null
|
||||||
|
this.reloadStatus = function (nodeId) {
|
||||||
|
let that = this
|
||||||
|
|
||||||
|
this.$post("/clusters/cluster/node/status")
|
||||||
|
.params({
|
||||||
|
nodeId: nodeId
|
||||||
|
})
|
||||||
|
.success(function (resp) {
|
||||||
|
this.installStatus = resp.data.installStatus
|
||||||
|
this.node.isInstalled = resp.data.isInstalled
|
||||||
|
if (this.node.isInstalled) {
|
||||||
|
this.isInstalling = false
|
||||||
|
this.isInstalled = true
|
||||||
|
this.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isInstalling) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let nodeId = this.node.id
|
||||||
|
let errMsg = this.installStatus.error
|
||||||
|
|
||||||
|
if (this.installStatus.errorCode.length > 0 || errMsg.length > 0) {
|
||||||
|
this.isInstalling = false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.installStatus.errorCode) {
|
||||||
|
case "EMPTY_LOGIN":
|
||||||
|
case "EMPTY_SSH_HOST":
|
||||||
|
case "EMPTY_SSH_PORT":
|
||||||
|
case "EMPTY_GRANT":
|
||||||
|
teaweb.warn("需要填写SSH登录信息", function () {
|
||||||
|
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
||||||
|
height: "30em",
|
||||||
|
callback: function () {
|
||||||
|
that.install()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return
|
||||||
|
case "SSH_LOGIN_FAILED":
|
||||||
|
teaweb.warn("SSH登录失败,请检查设置")
|
||||||
|
return
|
||||||
|
case "CREATE_ROOT_DIRECTORY_FAILED":
|
||||||
|
teaweb.warn("创建根目录失败,请检查目录权限或者手工创建:" + errMsg)
|
||||||
|
return
|
||||||
|
case "INSTALL_HELPER_FAILED":
|
||||||
|
teaweb.warn("安装助手失败:" + errMsg)
|
||||||
|
return
|
||||||
|
case "TEST_FAILED":
|
||||||
|
teaweb.warn("环境测试失败:" + errMsg)
|
||||||
|
return
|
||||||
|
case "RPC_TEST_FAILED":
|
||||||
|
teaweb.confirm("html:要安装的节点到API服务之间的RPC通讯测试失败,具体错误:" + errMsg + ",<br/>现在修改API信息?", function () {
|
||||||
|
window.location = "/api"
|
||||||
|
})
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
shouldReload = true
|
||||||
|
//teaweb.warn("安装失败:" + errMsg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.done(function () {
|
||||||
|
this.$delay(function () {
|
||||||
|
this.reloadStatus(nodeId)
|
||||||
|
}, 1000)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成
|
||||||
|
*/
|
||||||
|
this.finish = function () {
|
||||||
|
this.step = "finish"
|
||||||
|
}
|
||||||
|
|
||||||
|
this.createNext = function () {
|
||||||
|
teaweb.reload()
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -5,3 +5,11 @@
|
|||||||
.right-box {
|
.right-box {
|
||||||
top: 10em;
|
top: 10em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
line-height: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step.active {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
<td>SSH登录认证</td>
|
<td>SSH登录认证</td>
|
||||||
<td>
|
<td>
|
||||||
<div v-if="node.login != null && node.login.grant != null && node.login.grant.id > 0">
|
<div v-if="node.login != null && node.login.grant != null && node.login.grant.id > 0">
|
||||||
<a :href="'/clusters/grants/grant?grantId=' + node.login.grant.id">{{node.login.grant.name}}<span class="small">({{node.login.grant.methodName}})</span></a>
|
<a :href="'/clusters/grants/grant?grantId=' + node.login.grant.id">{{node.login.grant.name}}<span class="small grey">({{node.login.grant.methodName}})</span><span class="small grey" v-if="node.login.grant.username.length > 0">({{node.login.grant.username}})</span></a>
|
||||||
</div>
|
</div>
|
||||||
<span v-else class="disabled">
|
<span v-else class="disabled">
|
||||||
尚未设置
|
尚未设置
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>SSH登录认证</td>
|
<td>SSH登录认证</td>
|
||||||
<td>
|
<td>
|
||||||
<grant-selector :v-grant="grant"></grant-selector>
|
<grant-selector :v-grant="grant" :v-node-cluster-id="clusterId"></grant-selector>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ Tea.context(function () {
|
|||||||
id: this.node.login.grant.id,
|
id: this.node.login.grant.id,
|
||||||
name: this.node.login.grant.name,
|
name: this.node.login.grant.name,
|
||||||
method: this.node.login.grant.method,
|
method: this.node.login.grant.method,
|
||||||
methodName: this.node.login.grant.methodName
|
methodName: this.node.login.grant.methodName,
|
||||||
|
username: this.node.login.grant.username
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>SSH登录认证 *</td>
|
<td>SSH登录认证 *</td>
|
||||||
<td>
|
<td>
|
||||||
<grant-selector :v-grant="grant"></grant-selector>
|
<grant-selector :v-grant="grant" :v-node-cluster-id="clusterId"></grant-selector>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
29
web/views/@default/clusters/grants/selectPopup.css
Normal file
29
web/views/@default/clusters/grants/selectPopup.css
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
.grants-box {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
.grant-box {
|
||||||
|
float: left;
|
||||||
|
width: 12em;
|
||||||
|
height: 4.5em;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
border: 1px #ccc solid;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
padding: 0.5em 0.3em;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.grant-box .small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
.grant-box div.method {
|
||||||
|
margin-top: 0.3em;
|
||||||
|
}
|
||||||
|
.grant-box div.method .small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
.grant-box::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=selectPopup.css.map */
|
||||||
1
web/views/@default/clusters/grants/selectPopup.css.map
Normal file
1
web/views/@default/clusters/grants/selectPopup.css.map
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["selectPopup.less"],"names":[],"mappings":"AAAA;EACC,eAAA;;AAGD;EACC,WAAA;EACA,WAAA;EACA,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,mBAAA;EACA,sBAAA;EACA,oBAAA;EACA,oBAAA;EACA,gBAAA;EACA,eAAA;;AAXD,UAaC;EACC,gBAAA;;AAdF,UAiBC,IAAG;EACF,iBAAA;;AAlBF,UAiBC,IAAG,OAGF;EACC,gBAAA;;AAKH,UAAU;EACT,UAAA","file":"selectPopup.css"}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{$layout "layout_popup"}
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
<h3>选择认证</h3>
|
<h3>选择SSH认证</h3>
|
||||||
|
|
||||||
<form class="ui form">
|
<form class="ui form">
|
||||||
<div class="ui fields inline">
|
<div class="ui fields inline">
|
||||||
@@ -10,12 +10,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<table class="ui table">
|
<div class="ui divider"></div>
|
||||||
<tr>
|
|
||||||
<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><span v-if="grant.username.length > 0" class="small">({{grant.username}})</span></a>
|
<h4 v-if="suggestGrants.length > 0">可能的认证</h4>
|
||||||
<p class="comment">请点击选中某个认证。</p>
|
<div class="grants-box" v-if="suggestGrants.length > 0">
|
||||||
</td>
|
<div class="grant-box" v-for="grant in suggestGrants">
|
||||||
</tr>
|
<div :class="{blue:grantId == grant.id}" @click.prevent="selectGrant(grant)"><a href="">{{grant.name}}</a> <span v-if="grant.username.length > 0" class="small grey">({{grant.username}})</span>
|
||||||
</table>
|
<div class="method">
|
||||||
|
<span class="small grey">{{grant.methodName}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
|
||||||
|
<h4>全部认证</h4>
|
||||||
|
<div class="grants-box">
|
||||||
|
<div class="grant-box" v-for="grant in grants">
|
||||||
|
<div :class="{blue:grantId == grant.id}" @click.prevent="selectGrant(grant)"><a href="">{{grant.name}}</a> <span v-if="grant.username.length > 0" class="small grey">({{grant.username}})</span>
|
||||||
|
<div class="method">
|
||||||
|
<span class="small grey">{{grant.methodName}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
<p class="comment">请点击使用某个认证。</p>
|
||||||
|
|||||||
33
web/views/@default/clusters/grants/selectPopup.less
Normal file
33
web/views/@default/clusters/grants/selectPopup.less
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
.grants-box {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grant-box {
|
||||||
|
float: left;
|
||||||
|
width: 12em;
|
||||||
|
height: 4.5em;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
border: 1px #ccc solid;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
padding: 0.5em 0.3em;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.method {
|
||||||
|
margin-top: 0.3em;
|
||||||
|
|
||||||
|
.small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.grant-box::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
@@ -4,11 +4,11 @@
|
|||||||
|
|
||||||
<div class="ui four columns grid">
|
<div class="ui four columns grid">
|
||||||
<div class="ui column">
|
<div class="ui column">
|
||||||
<h4>域名<link-icon href="/ns"></link-icon></h4>
|
<h4>域名<link-icon href="/ns/domains"></link-icon></h4>
|
||||||
<div class="value"><span>{{board.countDomains}}</span>个</div>
|
<div class="value"><span>{{board.countDomains}}</span>个</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui column">
|
<div class="ui column">
|
||||||
<h4>记录<link-icon href="/ns"></link-icon></h4>
|
<h4>记录<link-icon href="/ns/domains"></link-icon></h4>
|
||||||
<div class="value"><span>{{board.countRecords}}</span>个</div>
|
<div class="value"><span>{{board.countRecords}}</span>个</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui column">
|
<div class="ui column">
|
||||||
|
|||||||
@@ -37,7 +37,10 @@ Tea.context(function () {
|
|||||||
|
|
||||||
// 清理节点
|
// 清理节点
|
||||||
this.cleanNode = function (nodeId) {
|
this.cleanNode = function (nodeId) {
|
||||||
teaweb.popup("/db/cleanPopup?nodeId=" + nodeId)
|
teaweb.popup("/db/cleanPopup?nodeId=" + nodeId, {
|
||||||
|
width: "44em",
|
||||||
|
height: "26em"
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示错误信息
|
// 显示错误信息
|
||||||
|
|||||||
@@ -61,6 +61,24 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
||||||
|
<!-- 华为云 -->
|
||||||
|
<tbody v-if="type == 'huaweiDNS'">
|
||||||
|
<tr>
|
||||||
|
<td>AccessKeyId *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="paramHuaweiAccessKeyId" maxlength="100"/>
|
||||||
|
<p class="comment">登录华为云控制台 -- 在"我的凭证 -- 访问密钥"中创建和获取。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>AccessKeySecret *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="paramHuaweiAccessKeySecret" maxlength="100"/>
|
||||||
|
<p class="comment">登录华为云控制台 -- 在"我的凭证 -- 访问密钥"中创建和获取。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
<!-- CloudFlare -->
|
<!-- CloudFlare -->
|
||||||
<tbody v-if="type == 'cloudFlare'">
|
<tbody v-if="type == 'cloudFlare'">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -43,6 +43,18 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
||||||
|
<!-- HuaweiDNS -->
|
||||||
|
<tbody v-if="provider.type == 'huaweiDNS'">
|
||||||
|
<tr>
|
||||||
|
<td>AccessKeyId</td>
|
||||||
|
<td>{{provider.apiParams.accessKeyId}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>AccessKeySecret</td>
|
||||||
|
<td>{{provider.apiParams.accessKeySecret}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
<!-- CloudFlare -->
|
<!-- CloudFlare -->
|
||||||
<tbody v-if="provider.type == 'cloudFlare'">
|
<tbody v-if="provider.type == 'cloudFlare'">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -60,6 +60,24 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
||||||
|
<!-- 华为云 -->
|
||||||
|
<tbody v-if="provider.type == 'huaweiDNS'">
|
||||||
|
<tr>
|
||||||
|
<td>AccessKeyId *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="paramHuaweiAccessKeyId" maxlength="100" v-model="provider.params.accessKeyId"/>
|
||||||
|
<p class="comment">登录华为云控制台 -- 在"我的凭证 -- 访问密钥"中创建和获取。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>AccessKeySecret *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="paramHuaweiAccessKeySecret" maxlength="100" v-model="provider.params.accessKeySecret"/>
|
||||||
|
<p class="comment">登录华为云控制台 -- 在"我的凭证 -- 访问密钥"中创建和获取。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
|
||||||
<!-- CloudFlare -->
|
<!-- CloudFlare -->
|
||||||
<tbody v-if="provider.type == 'cloudFlare'">
|
<tbody v-if="provider.type == 'cloudFlare'">
|
||||||
|
|||||||
@@ -47,10 +47,10 @@
|
|||||||
<input type="text" name="otpCode" placeholder="请输入OTP动态密码" maxlength="6"/>
|
<input type="text" name="otpCode" placeholder="请输入OTP动态密码" maxlength="6"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui field">
|
<div class="ui field" v-if="rememberLogin">
|
||||||
<a href="" @click.prevent="showMoreOptions()">更多选项 <i class="icon angle" :class="{down:!moreOptionsVisible, up:moreOptionsVisible}"></i> </a>
|
<a href="" @click.prevent="showMoreOptions()">更多选项 <i class="icon angle" :class="{down:!moreOptionsVisible, up:moreOptionsVisible}"></i> </a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui field" v-show="moreOptionsVisible">
|
<div class="ui field" v-if="rememberLogin" v-show="moreOptionsVisible">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" name="remember" value="1" checked="checked"/>
|
<input type="checkbox" name="remember" value="1" checked="checked"/>
|
||||||
<label>在这个电脑上记住登录(14天)</label>
|
<label>在这个电脑上记住登录(14天)</label>
|
||||||
|
|||||||
@@ -29,6 +29,46 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||||
|
</tr>
|
||||||
|
<tbody v-show="moreOptionsVisible">
|
||||||
|
<tr>
|
||||||
|
<td>SSH主机地址</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="node.login != null && node.login.params != null && node.login.params.host != null">
|
||||||
|
<span v-if="node.login.params.host.length > 0">{{node.login.params.host}}</span>
|
||||||
|
<span v-else class="disabled">尚未设置</span>
|
||||||
|
</div>
|
||||||
|
<div v-else class="disabled">
|
||||||
|
尚未设置
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SSH主机端口</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="node.login != null && node.login.params != null && node.login.params.host != null">
|
||||||
|
<span v-if="node.login.params.port > 0">{{node.login.params.port}}</span>
|
||||||
|
<span v-else class="disabled">尚未设置</span>
|
||||||
|
</div>
|
||||||
|
<span v-else class="disabled">
|
||||||
|
尚未设置
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SSH登录认证</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="node.login != null && node.login.grant != null && node.login.grant.id > 0">
|
||||||
|
<a :href="'/clusters/grants/grant?grantId=' + node.login.grant.id">{{node.login.grant.name}}<span class="small grey">({{node.login.grant.methodName}})</span><span class="small grey" v-if="node.login.grant.username.length > 0">({{node.login.grant.username}})</span></a>
|
||||||
|
</div>
|
||||||
|
<span v-else class="disabled">
|
||||||
|
尚未设置
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
@@ -39,12 +79,12 @@
|
|||||||
<td>
|
<td>
|
||||||
<div v-if="node.status.isActive">
|
<div v-if="node.status.isActive">
|
||||||
<span class="green">运行中</span>
|
<span class="green">运行中</span>
|
||||||
<!--<a href="" @click.prevent="stopNode()" v-if="!isStopping"><span>[通过SSH停止]</span></a>-->
|
<a href="" @click.prevent="stopNode()" v-if="!isStopping"><span>[通过SSH停止]</span></a>
|
||||||
<span v-if="isStopping">[停止中...]</span>
|
<span v-if="isStopping">[停止中...]</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<span class="red">已断开</span>
|
<span class="red">已断开</span>
|
||||||
<!--<a href="" @click.prevent="startNode()" v-if="node.isInstalled && !isStarting"><span>[通过SSH启动]</span></a>-->
|
<a href="" @click.prevent="startNode()" v-if="node.isInstalled && !isStarting"><span>[通过SSH启动]</span></a>
|
||||||
<span v-if="node.isInstalled && isStarting">[启动中...]</span>
|
<span v-if="node.isInstalled && isStarting">[启动中...]</span>
|
||||||
<a v-if="!node.isInstalled" :href="'/ns/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" ><span>去安装></span></a>
|
<a v-if="!node.isInstalled" :href="'/ns/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" ><span>去安装></span></a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<h3>修改节点</h3>
|
<h3>修改节点</h3>
|
||||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
<input type="hidden" name="nodeId" :value="node.id"/>
|
<input type="hidden" name="nodeId" :value="node.id"/>
|
||||||
|
<input type="hidden" name="loginId" :value="loginId"/>
|
||||||
<table class="ui table definition selectable">
|
<table class="ui table definition selectable">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">节点名称 *</td>
|
<td class="title">节点名称 *</td>
|
||||||
@@ -31,6 +32,26 @@
|
|||||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tbody v-show="moreOptionsVisible">
|
<tbody v-show="moreOptionsVisible">
|
||||||
|
<tr>
|
||||||
|
<td>SSH主机地址</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="sshHost" maxlength="64" v-model="sshHost"/>
|
||||||
|
<p class="comment">比如192.168.1.100</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SSH主机端口</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="sshPort" maxlength="5" v-model="sshPort"/>
|
||||||
|
<p class="comment">比如22。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SSH登录认证</td>
|
||||||
|
<td>
|
||||||
|
<grant-selector :v-grant="grant" :v-ns-cluster-id="clusterId"></grant-selector>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>是否启用</td>
|
<td>是否启用</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -5,4 +5,31 @@ Tea.context(function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.success = NotifySuccess("保存成功", "/ns/clusters/cluster/node?clusterId=" + this.clusterId + "&nodeId=" + this.node.id);
|
this.success = NotifySuccess("保存成功", "/ns/clusters/cluster/node?clusterId=" + this.clusterId + "&nodeId=" + this.node.id);
|
||||||
});
|
|
||||||
|
// 认证相关
|
||||||
|
this.grant = null
|
||||||
|
|
||||||
|
this.sshHost = ""
|
||||||
|
this.sshPort = ""
|
||||||
|
this.loginId = 0
|
||||||
|
if (this.node.login != null) {
|
||||||
|
this.loginId = this.node.login.id
|
||||||
|
|
||||||
|
if (this.node.login.params != null) {
|
||||||
|
this.sshHost = this.node.login.params.host
|
||||||
|
if (this.node.login.params.port > 0) {
|
||||||
|
this.sshPort = this.node.login.params.port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.node.login.grant != null && typeof this.node.login.grant.id != "undefined") {
|
||||||
|
this.grant = {
|
||||||
|
id: this.node.login.grant.id,
|
||||||
|
name: this.node.login.grant.name,
|
||||||
|
method: this.node.login.grant.method,
|
||||||
|
methodName: this.node.login.grant.methodName,
|
||||||
|
username: this.node.login.grant.username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
<csrf-token></csrf-token>
|
<csrf-token></csrf-token>
|
||||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||||
<ns-access-log-ref-box :v-access-log-ref="accessLogRef"></ns-access-log-ref-box>
|
<ns-access-log-ref-box :v-access-log-ref="accessLogRef" :v-is-parent="false"></ns-access-log-ref-box>
|
||||||
<submit-btn></submit-btn>
|
<submit-btn></submit-btn>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user