Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9734ed1cf8 | ||
|
|
548d122c64 | ||
|
|
c5205ef7a9 | ||
|
|
f71a27960b | ||
|
|
d747e656dc | ||
|
|
867215e2af | ||
|
|
3614b9f3b7 | ||
|
|
cbfa4c85c1 | ||
|
|
b9bef5042a | ||
|
|
46e523d005 | ||
|
|
fa2930dfc5 | ||
|
|
086ab15e8a | ||
|
|
c2e3e784a2 | ||
|
|
9dd01bd36e | ||
|
|
02d08b0762 | ||
|
|
cbd312e67d | ||
|
|
5084d9f87e | ||
|
|
3c3408624d | ||
|
|
6e8403390b | ||
|
|
ef9e5d4bbc | ||
|
|
c0b49948d7 | ||
|
|
48b066fb83 | ||
|
|
7d551d59db | ||
|
|
5a057857dc | ||
|
|
0a9cea722c | ||
|
|
f7eb7b1ec6 | ||
|
|
0eb57a734e | ||
|
|
82ff9a2b06 | ||
|
|
051a48bc73 | ||
|
|
6b9d5cf7a0 | ||
|
|
2e7d64d97b | ||
|
|
dd6050ee0b | ||
|
|
c954910728 | ||
|
|
0fe2bc4a54 | ||
|
|
9f39cd615f | ||
|
|
07bf21dbb4 | ||
|
|
43e8c65473 | ||
|
|
8a926eabbe |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
*_plus.go
|
*_plus.go
|
||||||
|
*-plus.sh
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
* `简单` - 架构简单清晰,安装简单,使用简单,运维简单
|
* `简单` - 架构简单清晰,安装简单,使用简单,运维简单
|
||||||
* `高扩展性` - 可以自由扩展新的节点,支持亿级数据
|
* `高扩展性` - 可以自由扩展新的节点,支持亿级数据
|
||||||
|
|
||||||
|
## 在线演示
|
||||||
|
* [http://demo.goedge.cn](http://demo.goedge.cn)
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
* [新手指南](https://edge.teaos.cn/docs/QuickStart/Index.md)
|
* [新手指南](https://edge.teaos.cn/docs/QuickStart/Index.md)
|
||||||
* [完整文档](https://edge.teaos.cn/docs)
|
* [完整文档](https://edge.teaos.cn/docs)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ function build() {
|
|||||||
DIST=$ROOT/"../dist/${NAME}"
|
DIST=$ROOT/"../dist/${NAME}"
|
||||||
OS=${1}
|
OS=${1}
|
||||||
ARCH=${2}
|
ARCH=${2}
|
||||||
|
TAG=${3}
|
||||||
|
|
||||||
if [ -z $OS ]; then
|
if [ -z $OS ]; then
|
||||||
echo "usage: build.sh OS ARCH"
|
echo "usage: build.sh OS ARCH"
|
||||||
@@ -15,9 +16,12 @@ function build() {
|
|||||||
echo "usage: build.sh OS ARCH"
|
echo "usage: build.sh OS ARCH"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
if [ -z $TAG ]; then
|
||||||
|
TAG="community"
|
||||||
|
fi
|
||||||
|
|
||||||
VERSION=$(lookup-version $ROOT/../internal/const/const.go)
|
VERSION=$(lookup-version $ROOT/../internal/const/const.go)
|
||||||
ZIP="${NAME}-${OS}-${ARCH}-v${VERSION}.zip"
|
ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip"
|
||||||
|
|
||||||
# check edge-api
|
# check edge-api
|
||||||
APINodeVersion=$(lookup-version $ROOT"/../../EdgeAPI/internal/const/const.go")
|
APINodeVersion=$(lookup-version $ROOT"/../../EdgeAPI/internal/const/const.go")
|
||||||
@@ -30,7 +34,7 @@ function build() {
|
|||||||
|
|
||||||
cd $ROOT"/../../EdgeAPI/build"
|
cd $ROOT"/../../EdgeAPI/build"
|
||||||
echo "=============================="
|
echo "=============================="
|
||||||
./build.sh $OS $ARCH
|
./build.sh $OS $ARCH $TAG
|
||||||
echo "=============================="
|
echo "=============================="
|
||||||
cd -
|
cd -
|
||||||
|
|
||||||
@@ -47,7 +51,7 @@ function build() {
|
|||||||
rm -f $DIST/web/tmp/*
|
rm -f $DIST/web/tmp/*
|
||||||
cp $ROOT/configs/server.template.yaml $DIST/configs/
|
cp $ROOT/configs/server.template.yaml $DIST/configs/
|
||||||
|
|
||||||
EDGE_API_ZIP_FILE=$ROOT"/../../EdgeAPI/dist/edge-api-${OS}-${ARCH}-v${APINodeVersion}.zip"
|
EDGE_API_ZIP_FILE=$ROOT"/../../EdgeAPI/dist/edge-api-${OS}-${ARCH}-${TAG}-v${APINodeVersion}.zip"
|
||||||
cp $EDGE_API_ZIP_FILE $DIST/
|
cp $EDGE_API_ZIP_FILE $DIST/
|
||||||
cd $DIST/
|
cd $DIST/
|
||||||
unzip -q $(basename $EDGE_API_ZIP_FILE)
|
unzip -q $(basename $EDGE_API_ZIP_FILE)
|
||||||
@@ -56,7 +60,7 @@ function build() {
|
|||||||
|
|
||||||
# build
|
# build
|
||||||
echo "building "${NAME}" ..."
|
echo "building "${NAME}" ..."
|
||||||
env GOOS=$OS GOARCH=$GOARCH go build -ldflags="-s -w" -o $DIST/bin/${NAME} $ROOT/../cmd/edge-admin/main.go
|
env GOOS=$OS GOARCH=$GOARCH go build -tags $TAG -ldflags="-s -w" -o $DIST/bin/${NAME} $ROOT/../cmd/edge-admin/main.go
|
||||||
|
|
||||||
# delete hidden files
|
# delete hidden files
|
||||||
find $DIST -name ".DS_Store" -delete
|
find $DIST -name ".DS_Store" -delete
|
||||||
@@ -88,4 +92,4 @@ function lookup-version() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
build $1 $2
|
build $1 $2 $3
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func main() {
|
|||||||
app := apps.NewAppCmd().
|
app := apps.NewAppCmd().
|
||||||
Version(teaconst.Version).
|
Version(teaconst.Version).
|
||||||
Product(teaconst.ProductName).
|
Product(teaconst.ProductName).
|
||||||
Usage(teaconst.ProcessName+" [-v|start|stop|restart|service|daemon|reset|recover]").
|
Usage(teaconst.ProcessName+" [-v|start|stop|restart|service|daemon|reset|recover|demo]").
|
||||||
Option("-h", "show this help").
|
Option("-h", "show this help").
|
||||||
Option("-v", "show version").
|
Option("-v", "show version").
|
||||||
Option("start", "start the service").
|
Option("start", "start the service").
|
||||||
@@ -57,6 +57,19 @@ func main() {
|
|||||||
}
|
}
|
||||||
fmt.Println("enter recovery mode successfully")
|
fmt.Println("enter recovery mode successfully")
|
||||||
})
|
})
|
||||||
|
app.On("demo", func() {
|
||||||
|
sock := gosock.NewTmpSock(teaconst.ProcessName)
|
||||||
|
if !sock.IsListening() {
|
||||||
|
fmt.Println("[ERROR]the service not started yet, you should start the service first")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err := sock.Send(&gosock.Command{Code: "demo"})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[ERROR]change demo mode failed: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("change demo mode successfully")
|
||||||
|
})
|
||||||
app.Run(func() {
|
app.Run(func() {
|
||||||
adminNode := nodes.NewAdminNode()
|
adminNode := nodes.NewAdminNode()
|
||||||
adminNode.Run()
|
adminNode.Run()
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -12,7 +12,7 @@ require (
|
|||||||
github.com/golang/protobuf v1.5.2
|
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-20210720054405-4030f271aa3f
|
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3
|
||||||
github.com/miekg/dns v1.1.35
|
github.com/miekg/dns v1.1.35
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
github.com/tealeg/xlsx/v3 v3.2.3
|
github.com/tealeg/xlsx/v3 v3.2.3
|
||||||
|
|||||||
15
go.sum
15
go.sum
@@ -64,13 +64,10 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
|||||||
github.com/iwind/TeaGo v0.0.0-20210628135026-38575a4ab060/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
github.com/iwind/TeaGo v0.0.0-20210628135026-38575a4ab060/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||||
github.com/iwind/TeaGo v0.0.0-20210720011303-fc255c995afa h1:woN88uEmRRUNFD7pRZEtX9heDcjFn0ClMxjF5ButKow=
|
github.com/iwind/TeaGo v0.0.0-20210720011303-fc255c995afa h1:woN88uEmRRUNFD7pRZEtX9heDcjFn0ClMxjF5ButKow=
|
||||||
github.com/iwind/TeaGo v0.0.0-20210720011303-fc255c995afa/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
github.com/iwind/TeaGo v0.0.0-20210720011303-fc255c995afa/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||||
github.com/iwind/gosock v0.0.0-20210706152215-08fe64b7a8a3 h1:BVHIjJU5RUX0grmvDtr3ZZ2z0hX+ideJRpg4NtBXZfs=
|
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c=
|
||||||
github.com/iwind/gosock v0.0.0-20210706152215-08fe64b7a8a3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
|
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
|
||||||
github.com/iwind/gosock v0.0.0-20210720054405-4030f271aa3f h1:+mKLTd5tCCLXK+iY5Xjz58hau6qFv9chGqcZ4FWUiIs=
|
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||||
github.com/iwind/gosock v0.0.0-20210720054405-4030f271aa3f/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
|
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
|
||||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
@@ -78,12 +75,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
|
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
|
||||||
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ func (this *AppCmd) Run(main func()) {
|
|||||||
|
|
||||||
// 版本号
|
// 版本号
|
||||||
func (this *AppCmd) runVersion() {
|
func (this *AppCmd) runVersion() {
|
||||||
fmt.Println(this.product+" v"+this.version, "(build: "+runtime.Version(), runtime.GOOS, runtime.GOARCH+")")
|
fmt.Println(this.product+" v"+this.version, "(build: "+runtime.Version(), runtime.GOOS, runtime.GOARCH, teaconst.Tag+")")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 帮助
|
// 帮助
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ func AllModuleMaps() []maps.Map {
|
|||||||
}
|
}
|
||||||
if teaconst.IsPlus {
|
if teaconst.IsPlus {
|
||||||
m = append(m, maps.Map{
|
m = append(m, maps.Map{
|
||||||
"name": "域名服务",
|
"name": "自建DNS",
|
||||||
"code": AdminModuleCodeNS,
|
"code": AdminModuleCodeNS,
|
||||||
"url": "/ns",
|
"url": "/ns",
|
||||||
})
|
})
|
||||||
|
|||||||
8
internal/const/build.go
Normal file
8
internal/const/build.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
// +build community
|
||||||
|
|
||||||
|
package teaconst
|
||||||
|
|
||||||
|
const BuildCommunity = true
|
||||||
|
const BuildPlus = false
|
||||||
|
const Tag = "community"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "0.2.5"
|
Version = "0.2.7"
|
||||||
|
|
||||||
ProductName = "Edge Admin"
|
ProductName = "Edge Admin"
|
||||||
ProcessName = "edge-admin"
|
ProcessName = "edge-admin"
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
// +build demo
|
|
||||||
|
|
||||||
package teaconst
|
|
||||||
|
|
||||||
const (
|
|
||||||
IsDemo = true
|
|
||||||
)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// +build !demo
|
|
||||||
|
|
||||||
package teaconst
|
|
||||||
|
|
||||||
const (
|
|
||||||
IsDemo = false
|
|
||||||
)
|
|
||||||
@@ -5,3 +5,8 @@ package teaconst
|
|||||||
var (
|
var (
|
||||||
IsRecoverMode = false
|
IsRecoverMode = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
IsDemoMode = false
|
||||||
|
ErrorDemoOperation = "DEMO模式下无法进行创建、修改、删除等操作"
|
||||||
|
)
|
||||||
|
|||||||
@@ -323,6 +323,9 @@ func (this *AdminNode) listenSock() error {
|
|||||||
case "recover":
|
case "recover":
|
||||||
teaconst.IsRecoverMode = true
|
teaconst.IsRecoverMode = true
|
||||||
_ = cmd.ReplyOk()
|
_ = cmd.ReplyOk()
|
||||||
|
case "demo":
|
||||||
|
teaconst.IsDemoMode = !teaconst.IsDemoMode
|
||||||
|
_ = cmd.ReplyOk()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -388,6 +388,10 @@ func (this *RPCClient) NSRecordRPC() pb.NSRecordServiceClient {
|
|||||||
return pb.NewNSRecordServiceClient(this.pickConn())
|
return pb.NewNSRecordServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) NSKeyRPC() pb.NSKeyServiceClient {
|
||||||
|
return pb.NewNSKeyServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) NSRouteRPC() pb.NSRouteServiceClient {
|
func (this *RPCClient) NSRouteRPC() pb.NSRouteServiceClient {
|
||||||
return pb.NewNSRouteServiceClient(this.pickConn())
|
return pb.NewNSRouteServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
|
||||||
|
|
||||||
package tasks
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
|
||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/Tea"
|
|
||||||
"github.com/iwind/TeaGo/logs"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
events.On(events.EventStart, func() {
|
|
||||||
task := NewAuthorityTask()
|
|
||||||
go task.Start()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type AuthorityTask struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAuthorityTask() *AuthorityTask {
|
|
||||||
return &AuthorityTask{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *AuthorityTask) Start() {
|
|
||||||
// 从缓存中读取
|
|
||||||
config := configs.ReadPlusConfig()
|
|
||||||
if config != nil {
|
|
||||||
teaconst.IsPlus = config.IsPlus
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始计时器
|
|
||||||
ticker := time.NewTicker(10 * time.Minute)
|
|
||||||
if Tea.IsTesting() {
|
|
||||||
// 快速测试
|
|
||||||
ticker = time.NewTicker(1 * time.Minute)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化的时候先获取一次
|
|
||||||
timeout := time.NewTimer(3 * time.Second)
|
|
||||||
<-timeout.C
|
|
||||||
err := this.Loop()
|
|
||||||
if err != nil {
|
|
||||||
logs.Println("[TASK][AuthorityTask]" + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// 定时获取
|
|
||||||
for range ticker.C {
|
|
||||||
err := this.Loop()
|
|
||||||
if err != nil {
|
|
||||||
logs.Println("[TASK][AuthorityTask]" + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *AuthorityTask) Loop() error {
|
|
||||||
// 如果还没有安装直接返回
|
|
||||||
if !setup.IsConfigured() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcClient, err := rpc.SharedRPC()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
resp, err := rpcClient.AuthorityKeyRPC().ReadAuthorityKey(rpcClient.Context(0), &pb.ReadAuthorityKeyRequest{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var oldState = teaconst.IsPlus
|
|
||||||
if resp.AuthorityKey != nil && len(resp.AuthorityKey.Value) > 0 && resp.AuthorityKey.DayTo >= timeutil.Format("Y-m-d") {
|
|
||||||
teaconst.IsPlus = true
|
|
||||||
} else {
|
|
||||||
teaconst.IsPlus = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldState != teaconst.IsPlus {
|
|
||||||
_ = configs.WritePlusConfig(&configs.PlusConfig{IsPlus: teaconst.IsPlus})
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 创建节点
|
// CreateNodeAction 创建节点
|
||||||
type CreateNodeAction struct {
|
type CreateNodeAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
}
|
}
|
||||||
@@ -57,8 +57,10 @@ func (this *CreateNodeAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
for _, route := range routesResp.Routes {
|
for _, route := range routesResp.Routes {
|
||||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
||||||
"name": route.Name,
|
"domainId": domainId,
|
||||||
"code": route.Code,
|
"domainName": clusterDNSResp.Domain.Name,
|
||||||
|
"name": route.Name,
|
||||||
|
"code": route.Code,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package node
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||||
@@ -37,6 +38,7 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 主集群
|
||||||
var clusterMap maps.Map = nil
|
var clusterMap maps.Map = nil
|
||||||
if node.NodeCluster != nil {
|
if node.NodeCluster != nil {
|
||||||
clusterId := node.NodeCluster.Id
|
clusterId := node.NodeCluster.Id
|
||||||
@@ -55,6 +57,16 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从集群
|
||||||
|
var secondaryClustersMaps = []maps.Map{}
|
||||||
|
for _, cluster := range node.SecondaryNodeClusters {
|
||||||
|
secondaryClustersMaps = append(secondaryClustersMaps, maps.Map{
|
||||||
|
"id": cluster.Id,
|
||||||
|
"name": cluster.Name,
|
||||||
|
"isOn": cluster.IsOn,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// IP地址
|
// IP地址
|
||||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
|
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
@@ -64,6 +76,7 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var ipAddresses = ipAddressesResp.Addresses
|
||||||
ipAddressMaps := []maps.Map{}
|
ipAddressMaps := []maps.Map{}
|
||||||
for _, addr := range ipAddressesResp.Addresses {
|
for _, addr := range ipAddressesResp.Addresses {
|
||||||
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
||||||
@@ -75,33 +88,56 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DNS相关
|
// DNS相关
|
||||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{NodeId: params.NodeId})
|
var clusters = []*pb.NodeCluster{node.NodeCluster}
|
||||||
if err != nil {
|
clusters = append(clusters, node.SecondaryNodeClusters...)
|
||||||
this.ErrorPage(err)
|
var recordMaps = []maps.Map{}
|
||||||
return
|
var routeMaps = []maps.Map{}
|
||||||
}
|
for _, cluster := range clusters {
|
||||||
dnsRouteMaps := []maps.Map{}
|
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
|
||||||
recordName := ""
|
NodeId: params.NodeId,
|
||||||
recordValue := ""
|
NodeClusterId: cluster.Id,
|
||||||
if dnsInfoResp.Node != nil {
|
})
|
||||||
recordName = dnsInfoResp.Node.NodeClusterDNSName + "." + dnsInfoResp.Node.DnsDomainName
|
if err != nil {
|
||||||
recordValue = dnsInfoResp.Node.IpAddr
|
this.ErrorPage(err)
|
||||||
for _, dnsInfo := range dnsInfoResp.Node.Routes {
|
return
|
||||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
}
|
||||||
"name": dnsInfo.Name,
|
var dnsInfo = dnsInfoResp.Node
|
||||||
"code": dnsInfo.Code,
|
if len(dnsInfo.DnsDomainName) == 0 || len(dnsInfo.NodeClusterDNSName) == 0 {
|
||||||
})
|
continue
|
||||||
|
}
|
||||||
|
var domainName = dnsInfo.DnsDomainName
|
||||||
|
|
||||||
|
// 默认线路
|
||||||
|
if len(dnsInfo.Routes) == 0 {
|
||||||
|
dnsInfo.Routes = append(dnsInfo.Routes, &pb.DNSRoute{})
|
||||||
|
} else {
|
||||||
|
for _, route := range dnsInfo.Routes {
|
||||||
|
routeMaps = append(routeMaps, maps.Map{
|
||||||
|
"domainName": domainName,
|
||||||
|
"code": route.Code,
|
||||||
|
"name": route.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range ipAddresses {
|
||||||
|
if !addr.CanAccess {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, route := range dnsInfo.Routes {
|
||||||
|
var recordType = "A"
|
||||||
|
if utils.IsIPv6(addr.Ip) {
|
||||||
|
recordType = "AAAA"
|
||||||
|
}
|
||||||
|
recordMaps = append(recordMaps, maps.Map{
|
||||||
|
"name": dnsInfo.NodeClusterDNSName + "." + domainName,
|
||||||
|
"type": recordType,
|
||||||
|
"route": route.Name,
|
||||||
|
"value": addr.Ip,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(dnsRouteMaps) == 0 {
|
|
||||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
|
||||||
"name": "",
|
|
||||||
"code": "",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["dnsRoutes"] = dnsRouteMaps
|
|
||||||
this.Data["dnsRecordName"] = recordName
|
|
||||||
this.Data["dnsRecordValue"] = recordValue
|
|
||||||
|
|
||||||
// 登录信息
|
// 登录信息
|
||||||
var loginMap maps.Map = nil
|
var loginMap maps.Map = nil
|
||||||
@@ -217,17 +253,20 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
"login": loginMap,
|
"secondaryClusters": secondaryClustersMaps,
|
||||||
"installDir": node.InstallDir,
|
"login": loginMap,
|
||||||
"isInstalled": node.IsInstalled,
|
"installDir": node.InstallDir,
|
||||||
"uniqueId": node.UniqueId,
|
"isInstalled": node.IsInstalled,
|
||||||
"secret": node.Secret,
|
"uniqueId": node.UniqueId,
|
||||||
"maxCPU": node.MaxCPU,
|
"secret": node.Secret,
|
||||||
"isOn": node.IsOn,
|
"maxCPU": node.MaxCPU,
|
||||||
|
"isOn": node.IsOn,
|
||||||
|
"records": recordMaps,
|
||||||
|
"routes": routeMaps,
|
||||||
|
|
||||||
"status": maps.Map{
|
"status": maps.Map{
|
||||||
"isActive": status.IsActive,
|
"isActive": status.IsActive,
|
||||||
|
|||||||
@@ -29,6 +29,6 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
if teaconst.IsPlus {
|
if teaconst.IsPlus {
|
||||||
this.RedirectURL("/clusters/cluster/node/boards?clusterId=" + fmt.Sprintf("%d", this.Data["clusterId"]) + "&nodeId=" + strconv.FormatInt(params.NodeId, 10))
|
this.RedirectURL("/clusters/cluster/node/boards?clusterId=" + fmt.Sprintf("%d", this.Data["clusterId"]) + "&nodeId=" + strconv.FormatInt(params.NodeId, 10))
|
||||||
} else {
|
} else {
|
||||||
this.RedirectURL("/clusters/cluster/node/detail?clusterId=" + fmt.Sprintf("%d", this.Data["clusterId"]) + strconv.FormatInt(params.NodeId, 10))
|
this.RedirectURL("/clusters/cluster/node/detail?clusterId=" + fmt.Sprintf("%d", this.Data["clusterId"]) + "&nodeId=" + strconv.FormatInt(params.NodeId, 10))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,44 +66,64 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DNS相关
|
// DNS相关
|
||||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{NodeId: params.NodeId})
|
var clusters = []*pb.NodeCluster{node.NodeCluster}
|
||||||
if err != nil {
|
clusters = append(clusters, node.SecondaryNodeClusters...)
|
||||||
this.ErrorPage(err)
|
var allDNSRouteMaps = map[int64][]maps.Map{} // domain id => routes
|
||||||
return
|
var routeMaps = map[int64][]maps.Map{} // domain id => routes
|
||||||
}
|
for _, cluster := range clusters {
|
||||||
nodeDNS := dnsInfoResp.Node
|
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
|
||||||
dnsRouteMaps := []maps.Map{}
|
NodeId: params.NodeId,
|
||||||
if nodeDNS != nil {
|
NodeClusterId: cluster.Id,
|
||||||
for _, dnsInfo := range nodeDNS.Routes {
|
})
|
||||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
if err != nil {
|
||||||
"name": dnsInfo.Name,
|
this.ErrorPage(err)
|
||||||
"code": dnsInfo.Code,
|
return
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
var dnsInfo = dnsInfoResp.Node
|
||||||
this.Data["dnsRoutes"] = dnsRouteMaps
|
if dnsInfo.DnsDomainId <= 0 || len(dnsInfo.DnsDomainName) == 0 {
|
||||||
this.Data["allDNSRoutes"] = []maps.Map{}
|
continue
|
||||||
if nodeDNS != nil {
|
}
|
||||||
this.Data["dnsDomainId"] = nodeDNS.DnsDomainId
|
var domainId = dnsInfo.DnsDomainId
|
||||||
} else {
|
var domainName = dnsInfo.DnsDomainName
|
||||||
this.Data["dnsDomainId"] = 0
|
if len(dnsInfo.Routes) > 0 {
|
||||||
}
|
for _, route := range dnsInfo.Routes {
|
||||||
if nodeDNS != nil && nodeDNS.DnsDomainId > 0 {
|
routeMaps[domainId] = append(routeMaps[domainId], maps.Map{
|
||||||
routesMaps := []maps.Map{}
|
"domainId": domainId,
|
||||||
|
"domainName": domainName,
|
||||||
|
"code": route.Code,
|
||||||
|
"name": route.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所有线路选项
|
||||||
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: dnsInfoResp.Node.DnsDomainId})
|
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: dnsInfoResp.Node.DnsDomainId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, route := range routesResp.Routes {
|
for _, route := range routesResp.Routes {
|
||||||
routesMaps = append(routesMaps, maps.Map{
|
allDNSRouteMaps[domainId] = append(allDNSRouteMaps[domainId], maps.Map{
|
||||||
"name": route.Name,
|
"domainId": domainId,
|
||||||
"code": route.Code,
|
"domainName": domainName,
|
||||||
|
"name": route.Name,
|
||||||
|
"code": route.Code,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.Data["allDNSRoutes"] = routesMaps
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var domainRoutes = []maps.Map{}
|
||||||
|
for _, m := range routeMaps {
|
||||||
|
domainRoutes = append(domainRoutes, m...)
|
||||||
|
}
|
||||||
|
this.Data["dnsRoutes"] = domainRoutes
|
||||||
|
|
||||||
|
var allDomainRoutes = []maps.Map{}
|
||||||
|
for _, m := range allDNSRouteMaps {
|
||||||
|
allDomainRoutes = append(allDomainRoutes, m...)
|
||||||
|
}
|
||||||
|
this.Data["allDNSRoutes"] = allDomainRoutes
|
||||||
|
|
||||||
// 登录信息
|
// 登录信息
|
||||||
var loginMap maps.Map = nil
|
var loginMap maps.Map = nil
|
||||||
if node.Login != nil {
|
if node.Login != nil {
|
||||||
@@ -188,7 +208,7 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
var m = maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
"ipAddresses": ipAddressMaps,
|
"ipAddresses": ipAddressMaps,
|
||||||
@@ -202,23 +222,29 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
|
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 所有集群
|
if node.NodeCluster != nil {
|
||||||
resp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClusters(this.AdminContext(), &pb.FindAllEnabledNodeClustersRequest{})
|
m["primaryCluster"] = maps.Map{
|
||||||
if err != nil {
|
"id": node.NodeCluster.Id,
|
||||||
this.ErrorPage(err)
|
"name": node.NodeCluster.Name,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m["primaryCluster"] = nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
if len(node.SecondaryNodeClusters) > 0 {
|
||||||
return
|
var secondaryClusterMaps = []maps.Map{}
|
||||||
|
for _, cluster := range node.SecondaryNodeClusters {
|
||||||
|
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||||
|
"id": cluster.Id,
|
||||||
|
"name": cluster.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
m["secondaryClusters"] = secondaryClusterMaps
|
||||||
|
} else {
|
||||||
|
m["secondaryClusters"] = []interface{}{}
|
||||||
}
|
}
|
||||||
clusterMaps := []maps.Map{}
|
|
||||||
for _, cluster := range resp.NodeClusters {
|
this.Data["node"] = m
|
||||||
clusterMaps = append(clusterMaps, maps.Map{
|
|
||||||
"id": cluster.Id,
|
|
||||||
"name": cluster.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["clusters"] = clusterMaps
|
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
@@ -230,7 +256,8 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
RegionId int64
|
RegionId int64
|
||||||
Name string
|
Name string
|
||||||
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
||||||
ClusterId int64
|
PrimaryClusterId int64
|
||||||
|
SecondaryClusterIds []byte
|
||||||
GrantId int64
|
GrantId int64
|
||||||
SshHost string
|
SshHost string
|
||||||
SshPort int
|
SshPort int
|
||||||
@@ -256,8 +283,17 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
Require("请输入节点名称")
|
Require("请输入节点名称")
|
||||||
|
|
||||||
// TODO 检查cluster
|
// TODO 检查cluster
|
||||||
if params.ClusterId <= 0 {
|
if params.PrimaryClusterId <= 0 {
|
||||||
this.Fail("请选择所在集群")
|
this.Fail("请选择节点所在主集群")
|
||||||
|
}
|
||||||
|
|
||||||
|
var secondaryClusterIds = []int64{}
|
||||||
|
if len(params.SecondaryClusterIds) > 0 {
|
||||||
|
err := json.Unmarshal(params.SecondaryClusterIds, &secondaryClusterIds)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IP地址
|
// IP地址
|
||||||
@@ -325,18 +361,19 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
|
|
||||||
// 保存
|
// 保存
|
||||||
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
|
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
NodeGroupId: params.GroupId,
|
NodeGroupId: params.GroupId,
|
||||||
NodeRegionId: params.RegionId,
|
NodeRegionId: params.RegionId,
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
NodeClusterId: params.ClusterId,
|
NodeClusterId: params.PrimaryClusterId,
|
||||||
NodeLogin: loginInfo,
|
SecondaryNodeClusterIds: secondaryClusterIds,
|
||||||
MaxCPU: params.MaxCPU,
|
NodeLogin: loginInfo,
|
||||||
IsOn: params.IsOn,
|
MaxCPU: params.MaxCPU,
|
||||||
DnsDomainId: params.DnsDomainId,
|
IsOn: params.IsOn,
|
||||||
DnsRoutes: dnsRouteCodes,
|
DnsDomainId: params.DnsDomainId,
|
||||||
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
DnsRoutes: dnsRouteCodes,
|
||||||
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
||||||
|
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -156,6 +156,16 @@ func (this *NodesAction) RunGet(params struct {
|
|||||||
dnsRouteNames = append(dnsRouteNames, route.Name)
|
dnsRouteNames = append(dnsRouteNames, route.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从集群
|
||||||
|
var secondaryClusterMaps []maps.Map
|
||||||
|
for _, secondaryCluster := range node.SecondaryNodeClusters {
|
||||||
|
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||||
|
"id": secondaryCluster.Id,
|
||||||
|
"name": secondaryCluster.Name,
|
||||||
|
"isOn": secondaryCluster.IsOn,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
nodeMaps = append(nodeMaps, maps.Map{
|
nodeMaps = append(nodeMaps, maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
@@ -183,11 +193,12 @@ func (this *NodesAction) RunGet(params struct {
|
|||||||
"id": node.NodeCluster.Id,
|
"id": node.NodeCluster.Id,
|
||||||
"name": node.NodeCluster.Name,
|
"name": node.NodeCluster.Name,
|
||||||
},
|
},
|
||||||
"isSynced": isSynced,
|
"secondaryClusters": secondaryClusterMaps,
|
||||||
"ipAddresses": ipAddresses,
|
"isSynced": isSynced,
|
||||||
"group": groupMap,
|
"ipAddresses": ipAddresses,
|
||||||
"region": regionMap,
|
"group": groupMap,
|
||||||
"dnsRouteNames": dnsRouteNames,
|
"region": regionMap,
|
||||||
|
"dnsRouteNames": dnsRouteNames,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.Data["nodes"] = nodeMaps
|
this.Data["nodes"] = nodeMaps
|
||||||
|
|||||||
@@ -63,6 +63,14 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
// 创建日志
|
// 创建日志
|
||||||
defer this.CreateLog(oplogs.LevelInfo, "修改集群 %d DNS设置", params.ClusterId)
|
defer this.CreateLog(oplogs.LevelInfo, "修改集群 %d DNS设置", params.ClusterId)
|
||||||
|
|
||||||
|
if params.DnsDomainId <= 0 {
|
||||||
|
this.Fail("请选择集群的主域名")
|
||||||
|
}
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("dnsName", params.DnsName).
|
||||||
|
Require("请输入DNS子域名")
|
||||||
|
|
||||||
// 检查DNS名称
|
// 检查DNS名称
|
||||||
if len(params.DnsName) > 0 {
|
if len(params.DnsName) > 0 {
|
||||||
if !domainutils.ValidateDomainFormat(params.DnsName) {
|
if !domainutils.ValidateDomainFormat(params.DnsName) {
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
this.FailField("username", "请输入SSH登录用户名")
|
this.FailField("username", "请输入SSH登录用户名")
|
||||||
}
|
}
|
||||||
case "privateKey":
|
case "privateKey":
|
||||||
|
if len(params.Username) == 0 {
|
||||||
|
this.FailField("username", "请输入SSH登录用户名")
|
||||||
|
}
|
||||||
if len(params.PrivateKey) == 0 {
|
if len(params.PrivateKey) == 0 {
|
||||||
this.FailField("privateKey", "请输入RSA私钥")
|
this.FailField("privateKey", "请输入RSA私钥")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
this.FailField("username", "请输入SSH登录用户名")
|
this.FailField("username", "请输入SSH登录用户名")
|
||||||
}
|
}
|
||||||
case "privateKey":
|
case "privateKey":
|
||||||
|
if len(params.Username) == 0 {
|
||||||
|
this.FailField("username", "请输入SSH登录用户名")
|
||||||
|
}
|
||||||
if len(params.PrivateKey) == 0 {
|
if len(params.PrivateKey) == 0 {
|
||||||
this.FailField("privateKey", "请输入RSA私钥")
|
this.FailField("privateKey", "请输入RSA私钥")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,6 +235,16 @@ func (this *IndexAction) searchNodes(keyword string) {
|
|||||||
dnsRouteNames = append(dnsRouteNames, route.Name)
|
dnsRouteNames = append(dnsRouteNames, route.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从集群
|
||||||
|
var secondaryClusterMaps []maps.Map
|
||||||
|
for _, secondaryCluster := range node.SecondaryNodeClusters {
|
||||||
|
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||||
|
"id": secondaryCluster.Id,
|
||||||
|
"name": secondaryCluster.Name,
|
||||||
|
"isOn": secondaryCluster.IsOn,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
nodeMaps = append(nodeMaps, maps.Map{
|
nodeMaps = append(nodeMaps, maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
@@ -260,11 +270,12 @@ func (this *IndexAction) searchNodes(keyword string) {
|
|||||||
"id": node.NodeCluster.Id,
|
"id": node.NodeCluster.Id,
|
||||||
"name": node.NodeCluster.Name,
|
"name": node.NodeCluster.Name,
|
||||||
},
|
},
|
||||||
"isSynced": isSynced,
|
"secondaryClusters": secondaryClusterMaps,
|
||||||
"ipAddresses": ipAddresses,
|
"isSynced": isSynced,
|
||||||
"group": groupMap,
|
"ipAddresses": ipAddresses,
|
||||||
"region": regionMap,
|
"group": groupMap,
|
||||||
"dnsRouteNames": dnsRouteNames,
|
"region": regionMap,
|
||||||
|
"dnsRouteNames": dnsRouteNames,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.Data["nodes"] = nodeMaps
|
this.Data["nodes"] = nodeMaps
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ func init() {
|
|||||||
EndHelpers().
|
EndHelpers().
|
||||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
|
||||||
Post("/options", new(OptionsAction)).
|
Post("/options", new(OptionsAction)).
|
||||||
|
GetPost("/selectPopup", new(SelectPopupAction)).
|
||||||
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
|
|||||||
64
internal/web/actions/default/clusters/selectPopup.go
Normal file
64
internal/web/actions/default/clusters/selectPopup.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package clusters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SelectPopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SelectPopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SelectPopupAction) RunGet(params struct {
|
||||||
|
SelectedClusterIds string
|
||||||
|
}) {
|
||||||
|
var selectedIds = utils.SplitNumbers(params.SelectedClusterIds)
|
||||||
|
|
||||||
|
countResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var count = countResp.Count
|
||||||
|
var page = this.NewPage(count)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
clustersResp, err := this.RPC().NodeClusterRPC().ListEnabledNodeClusters(this.AdminContext(), &pb.ListEnabledNodeClustersRequest{
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var clusterMaps = []maps.Map{}
|
||||||
|
for _, cluster := range clustersResp.NodeClusters {
|
||||||
|
// 节点数
|
||||||
|
countNodesResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{NodeClusterId: cluster.Id})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var countNodes = countNodesResp.Count
|
||||||
|
|
||||||
|
clusterMaps = append(clusterMaps, maps.Map{
|
||||||
|
"id": cluster.Id,
|
||||||
|
"name": cluster.Name,
|
||||||
|
"isOn": cluster.IsOn,
|
||||||
|
"countNodes": countNodes,
|
||||||
|
"isSelected": lists.ContainsInt64(selectedIds, cluster.Id),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["clusters"] = clusterMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -43,16 +43,21 @@ func (this *ClustersPopupAction) RunGet(params struct {
|
|||||||
for _, cluster := range clustersResp.NodeClusters {
|
for _, cluster := range clustersResp.NodeClusters {
|
||||||
isOk := false
|
isOk := false
|
||||||
if len(cluster.Name) > 0 {
|
if len(cluster.Name) > 0 {
|
||||||
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
for _, recordType := range []string{"A", "AAAA"} {
|
||||||
DnsDomainId: params.DomainId,
|
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
||||||
Name: cluster.DnsName,
|
DnsDomainId: params.DomainId,
|
||||||
Type: "A",
|
Name: cluster.DnsName,
|
||||||
})
|
Type: recordType,
|
||||||
if err != nil {
|
})
|
||||||
this.ErrorPage(err)
|
if err != nil {
|
||||||
return
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if checkResp.IsOk {
|
||||||
|
isOk = true
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
isOk = checkResp.IsOk
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clusterMaps = append(clusterMaps, maps.Map{
|
clusterMaps = append(clusterMaps, maps.Map{
|
||||||
|
|||||||
@@ -33,12 +33,17 @@ func ValidateDomainFormat(domain string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ConvertRoutesToMaps 转换线路列表
|
// ConvertRoutesToMaps 转换线路列表
|
||||||
func ConvertRoutesToMaps(routes []*pb.DNSRoute) []maps.Map {
|
func ConvertRoutesToMaps(info *pb.NodeDNSInfo) []maps.Map {
|
||||||
|
if info == nil {
|
||||||
|
return []maps.Map{}
|
||||||
|
}
|
||||||
result := []maps.Map{}
|
result := []maps.Map{}
|
||||||
for _, route := range routes {
|
for _, route := range info.Routes {
|
||||||
result = append(result, maps.Map{
|
result = append(result, maps.Map{
|
||||||
"name": route.Name,
|
"name": route.Name,
|
||||||
"code": route.Code,
|
"code": route.Code,
|
||||||
|
"domainId": info.DnsDomainId,
|
||||||
|
"domainName": info.DnsDomainName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package domains
|
package domains
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"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"
|
||||||
@@ -55,10 +56,14 @@ func (this *NodesPopupAction) RunGet(params struct {
|
|||||||
// 检查是否有域名解析记录
|
// 检查是否有域名解析记录
|
||||||
isOk := false
|
isOk := false
|
||||||
if len(route.Name) > 0 && len(node.IpAddr) > 0 && len(cluster.DnsName) > 0 {
|
if len(route.Name) > 0 && len(node.IpAddr) > 0 && len(cluster.DnsName) > 0 {
|
||||||
|
var recordType = "A"
|
||||||
|
if utils.IsIPv6(node.IpAddr) {
|
||||||
|
recordType = "AAAA"
|
||||||
|
}
|
||||||
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
||||||
DnsDomainId: params.DomainId,
|
DnsDomainId: params.DomainId,
|
||||||
Name: cluster.DnsName,
|
Name: cluster.DnsName,
|
||||||
Type: "A",
|
Type: recordType,
|
||||||
Route: route.Code,
|
Route: route.Code,
|
||||||
Value: node.IpAddr,
|
Value: node.IpAddr,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ func (this *UpdateNodePopupAction) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *UpdateNodePopupAction) RunGet(params struct {
|
func (this *UpdateNodePopupAction) RunGet(params struct {
|
||||||
NodeId int64
|
ClusterId int64
|
||||||
|
NodeId int64
|
||||||
}) {
|
}) {
|
||||||
this.Data["nodeId"] = params.NodeId
|
this.Data["nodeId"] = params.NodeId
|
||||||
|
|
||||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{NodeId: params.NodeId})
|
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
|
||||||
|
NodeId: params.NodeId,
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -35,7 +39,7 @@ func (this *UpdateNodePopupAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.Data["ipAddr"] = dnsInfo.IpAddr
|
this.Data["ipAddr"] = dnsInfo.IpAddr
|
||||||
this.Data["routes"] = domainutils.ConvertRoutesToMaps(dnsInfo.Routes)
|
this.Data["routes"] = domainutils.ConvertRoutesToMaps(dnsInfo)
|
||||||
this.Data["domainId"] = dnsInfo.DnsDomainId
|
this.Data["domainId"] = dnsInfo.DnsDomainId
|
||||||
this.Data["domainName"] = dnsInfo.DnsDomainName
|
this.Data["domainName"] = dnsInfo.DnsDomainName
|
||||||
|
|
||||||
@@ -50,13 +54,17 @@ func (this *UpdateNodePopupAction) RunGet(params struct {
|
|||||||
if len(routesResp.Routes) > 0 {
|
if len(routesResp.Routes) > 0 {
|
||||||
for _, route := range routesResp.Routes {
|
for _, route := range routesResp.Routes {
|
||||||
allRouteMaps = append(allRouteMaps, maps.Map{
|
allRouteMaps = append(allRouteMaps, maps.Map{
|
||||||
"name": route.Name,
|
"name": route.Name,
|
||||||
"code": route.Code,
|
"code": route.Code,
|
||||||
|
"domainName": dnsInfo.DnsDomainName,
|
||||||
|
"domainId": dnsInfo.DnsDomainId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 筛选
|
// 筛选
|
||||||
this.Data["routes"] = domainutils.ConvertRoutesToMaps(domainutils.FilterRoutes(dnsInfo.Routes, routesResp.Routes))
|
var routes = domainutils.FilterRoutes(dnsInfo.Routes, routesResp.Routes)
|
||||||
|
dnsInfo.Routes = routes
|
||||||
|
this.Data["routes"] = domainutils.ConvertRoutesToMaps(dnsInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.Data["allRoutes"] = allRouteMaps
|
this.Data["allRoutes"] = allRouteMaps
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
|
|
||||||
Auth *helpers.UserShouldAuth
|
Auth *helpers.UserShouldAuth
|
||||||
}) {
|
}) {
|
||||||
|
// DEMO模式
|
||||||
|
this.Data["isDemo"] = teaconst.IsDemoMode
|
||||||
|
|
||||||
// 检查系统是否已经配置过
|
// 检查系统是否已经配置过
|
||||||
if !setup.IsConfigured() {
|
if !setup.IsConfigured() {
|
||||||
this.RedirectURL("/setup")
|
this.RedirectURL("/setup")
|
||||||
|
|||||||
@@ -10,12 +10,16 @@ type DeleteAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *DeleteAction) RunPost(params struct {
|
func (this *DeleteAction) RunPost(params struct {
|
||||||
NodeId int64
|
ClusterId int64
|
||||||
|
NodeId int64
|
||||||
}) {
|
}) {
|
||||||
// 创建日志
|
// 创建日志
|
||||||
defer this.CreateLogInfo("删除节点", params.NodeId)
|
defer this.CreateLogInfo("从集群 %d 中删除节点 %d", params.ClusterId, params.NodeId)
|
||||||
|
|
||||||
_, err := this.RPC().NodeRPC().DeleteNode(this.AdminContext(), &pb.DeleteNodeRequest{NodeId: params.NodeId})
|
_, err := this.RPC().NodeRPC().DeleteNodeFromNodeCluster(this.AdminContext(), &pb.DeleteNodeFromNodeClusterRequest{
|
||||||
|
NodeId: params.NodeId,
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package domains
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/domainutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
)
|
)
|
||||||
@@ -19,6 +20,14 @@ func (this *DomainAction) Init() {
|
|||||||
func (this *DomainAction) RunGet(params struct {
|
func (this *DomainAction) RunGet(params struct {
|
||||||
DomainId int64
|
DomainId int64
|
||||||
}) {
|
}) {
|
||||||
|
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var countRecords = this.Data.GetMap("domain").GetInt64("countRecords")
|
||||||
|
var countKeys = this.Data.GetMap("domain").GetInt64("countKeys")
|
||||||
|
|
||||||
// 域名信息
|
// 域名信息
|
||||||
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -50,11 +59,13 @@ func (this *DomainAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.Data["domain"] = maps.Map{
|
this.Data["domain"] = maps.Map{
|
||||||
"id": domain.Id,
|
"id": domain.Id,
|
||||||
"name": domain.Name,
|
"name": domain.Name,
|
||||||
"isOn": domain.IsOn,
|
"isOn": domain.IsOn,
|
||||||
"cluster": clusterMap,
|
"cluster": clusterMap,
|
||||||
"user": userMap,
|
"user": userMap,
|
||||||
|
"countRecords": countRecords,
|
||||||
|
"countKeys": countKeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
|
|||||||
55
internal/web/actions/default/ns/domains/domainutils/utils.go
Normal file
55
internal/web/actions/default/ns/domains/domainutils/utils.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package domainutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitDomain 初始化域名信息
|
||||||
|
func InitDomain(parent *actionutils.ParentAction, domainId int64) error {
|
||||||
|
rpcClient, err := rpc.SharedRPC()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
domainResp, err := rpcClient.NSDomainRPC().FindEnabledNSDomain(parent.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: domainId})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var domain = domainResp.NsDomain
|
||||||
|
if domain == nil {
|
||||||
|
return errors.New("InitDomain: can not find domain with id '" + types.String(domainId) + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录数量
|
||||||
|
countRecordsResp, err := rpcClient.NSRecordRPC().CountAllEnabledNSRecords(parent.AdminContext(), &pb.CountAllEnabledNSRecordsRequest{
|
||||||
|
NsDomainId: domainId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var countRecords = countRecordsResp.Count
|
||||||
|
|
||||||
|
// Key数量
|
||||||
|
countKeysResp, err := rpcClient.NSKeyRPC().CountAllEnabledNSKeys(parent.AdminContext(), &pb.CountAllEnabledNSKeysRequest{
|
||||||
|
NsDomainId: domainId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var countKeys = countKeysResp.Count
|
||||||
|
|
||||||
|
parent.Data["domain"] = maps.Map{
|
||||||
|
"id": domain.Id,
|
||||||
|
"name": domain.Name,
|
||||||
|
"countRecords": countRecords,
|
||||||
|
"countKeys": countKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
86
internal/web/actions/default/ns/domains/keys/createPopup.go
Normal file
86
internal/web/actions/default/ns/domains/keys/createPopup.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package keys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreatePopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunGet(params struct {
|
||||||
|
DomainId int64
|
||||||
|
}) {
|
||||||
|
this.Data["domainId"] = params.DomainId
|
||||||
|
|
||||||
|
// 所有算法
|
||||||
|
var algorithmMaps = []maps.Map{}
|
||||||
|
for _, algo := range dnsconfigs.FindAllKeyAlgorithmTypes() {
|
||||||
|
algorithmMaps = append(algorithmMaps, maps.Map{
|
||||||
|
"name": algo.Name,
|
||||||
|
"code": algo.Code,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["algorithms"] = algorithmMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunPost(params struct {
|
||||||
|
DomainId int64
|
||||||
|
Name string
|
||||||
|
Algo string
|
||||||
|
Secret string
|
||||||
|
SecretType string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
var keyId int64 = 0
|
||||||
|
defer func() {
|
||||||
|
this.CreateLogInfo("创建DNS密钥 %d", keyId)
|
||||||
|
}()
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("name", params.Name).
|
||||||
|
Require("请输入密钥名称").
|
||||||
|
Field("algo", params.Algo).
|
||||||
|
Require("请选择算法").
|
||||||
|
Field("secret", params.Secret).
|
||||||
|
Require("请输入密码")
|
||||||
|
|
||||||
|
// 校验密码
|
||||||
|
if params.SecretType == dnsconfigs.NSKeySecretTypeBase64 {
|
||||||
|
_, err := base64.StdEncoding.DecodeString(params.Secret)
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("secret", "请输入BASE64格式的密码或者选择明文")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createResp, err := this.RPC().NSKeyRPC().CreateNSKey(this.AdminContext(), &pb.CreateNSKeyRequest{
|
||||||
|
NsDomainId: params.DomainId,
|
||||||
|
NsZoneId: 0,
|
||||||
|
Name: params.Name,
|
||||||
|
Algo: params.Algo,
|
||||||
|
Secret: params.Secret,
|
||||||
|
SecretType: params.SecretType,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
keyId = createResp.NsKeyId
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
26
internal/web/actions/default/ns/domains/keys/delete.go
Normal file
26
internal/web/actions/default/ns/domains/keys/delete.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package keys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DeleteAction) RunPost(params struct {
|
||||||
|
KeyId int64
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("删除DNS密钥 %d", params.KeyId)
|
||||||
|
|
||||||
|
_, err := this.RPC().NSKeyRPC().DeleteNSKey(this.AdminContext(), &pb.DeleteNSKeyRequest{NsKeyId: params.KeyId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package keys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
|
"github.com/iwind/TeaGo/rands"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GenerateSecretAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GenerateSecretAction) RunPost(params struct {
|
||||||
|
SecretType string
|
||||||
|
}) {
|
||||||
|
switch params.SecretType {
|
||||||
|
case dnsconfigs.NSKeySecretTypeClear:
|
||||||
|
this.Data["secret"] = rands.HexString(128)
|
||||||
|
case dnsconfigs.NSKeySecretTypeBase64:
|
||||||
|
this.Data["secret"] = base64.StdEncoding.EncodeToString([]byte(rands.HexString(128)))
|
||||||
|
default:
|
||||||
|
this.Data["secret"] = rands.HexString(128)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
68
internal/web/actions/default/ns/domains/keys/index.go
Normal file
68
internal/web/actions/default/ns/domains/keys/index.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package keys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/domainutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "key")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
DomainId int64
|
||||||
|
}) {
|
||||||
|
// 初始化域名信息
|
||||||
|
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数量
|
||||||
|
countResp, err := this.RPC().NSKeyRPC().CountAllEnabledNSKeys(this.AdminContext(), &pb.CountAllEnabledNSKeysRequest{
|
||||||
|
NsDomainId: params.DomainId,
|
||||||
|
NsZoneId: 0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var page = this.NewPage(countResp.Count)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
// 列表
|
||||||
|
keysResp, err := this.RPC().NSKeyRPC().ListEnabledNSKeys(this.AdminContext(), &pb.ListEnabledNSKeysRequest{
|
||||||
|
NsDomainId: params.DomainId,
|
||||||
|
NsZoneId: 0,
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var keyMaps = []maps.Map{}
|
||||||
|
for _, key := range keysResp.NsKeys {
|
||||||
|
keyMaps = append(keyMaps, maps.Map{
|
||||||
|
"id": key.Id,
|
||||||
|
"name": key.Name,
|
||||||
|
"secret": key.Secret,
|
||||||
|
"secretTypeName": dnsconfigs.FindKeySecretTypeName(key.SecretType),
|
||||||
|
"algoName": dnsconfigs.FindKeyAlgorithmTypeName(key.Algo),
|
||||||
|
"isOn": key.IsOn,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["keys"] = keyMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
100
internal/web/actions/default/ns/domains/keys/updatePopup.go
Normal file
100
internal/web/actions/default/ns/domains/keys/updatePopup.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package keys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdatePopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdatePopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdatePopupAction) RunGet(params struct {
|
||||||
|
KeyId int64
|
||||||
|
}) {
|
||||||
|
keyResp, err := this.RPC().NSKeyRPC().FindEnabledNSKey(this.AdminContext(), &pb.FindEnabledNSKeyRequest{NsKeyId: params.KeyId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var key = keyResp.NsKey
|
||||||
|
if key == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["key"] = maps.Map{
|
||||||
|
"id": key.Id,
|
||||||
|
"name": key.Name,
|
||||||
|
"algo": key.Algo,
|
||||||
|
"secret": key.Secret,
|
||||||
|
"secretType": key.SecretType,
|
||||||
|
"isOn": key.IsOn,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所有算法
|
||||||
|
var algorithmMaps = []maps.Map{}
|
||||||
|
for _, algo := range dnsconfigs.FindAllKeyAlgorithmTypes() {
|
||||||
|
algorithmMaps = append(algorithmMaps, maps.Map{
|
||||||
|
"name": algo.Name,
|
||||||
|
"code": algo.Code,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["algorithms"] = algorithmMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdatePopupAction) RunPost(params struct {
|
||||||
|
KeyId int64
|
||||||
|
Name string
|
||||||
|
Algo string
|
||||||
|
Secret string
|
||||||
|
SecretType string
|
||||||
|
IsOn bool
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
this.CreateLogInfo("修改DNS密钥 %d", params.KeyId)
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("name", params.Name).
|
||||||
|
Require("请输入密钥名称").
|
||||||
|
Field("algo", params.Algo).
|
||||||
|
Require("请选择算法").
|
||||||
|
Field("secret", params.Secret).
|
||||||
|
Require("请输入密码")
|
||||||
|
|
||||||
|
// 校验密码
|
||||||
|
if params.SecretType == dnsconfigs.NSKeySecretTypeBase64 {
|
||||||
|
_, err := base64.StdEncoding.DecodeString(params.Secret)
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("secret", "请输入BASE64格式的密码或者选择明文")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := this.RPC().NSKeyRPC().UpdateNSKey(this.AdminContext(), &pb.UpdateNSKeyRequest{
|
||||||
|
NsKeyId: params.KeyId,
|
||||||
|
Name: params.Name,
|
||||||
|
Algo: params.Algo,
|
||||||
|
Secret: params.Secret,
|
||||||
|
SecretType: params.SecretType,
|
||||||
|
IsOn: params.IsOn,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ package records
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/domainutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
"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"
|
||||||
@@ -23,25 +24,16 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
Keyword string
|
Keyword string
|
||||||
RouteId int64
|
RouteId int64
|
||||||
}) {
|
}) {
|
||||||
this.Data["type"] = params.Type
|
// 初始化域名信息
|
||||||
this.Data["keyword"] = params.Keyword
|
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||||
this.Data["routeId"] = params.RouteId
|
|
||||||
|
|
||||||
// 域名信息
|
|
||||||
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
domain := domainResp.NsDomain
|
|
||||||
if domain == nil {
|
this.Data["type"] = params.Type
|
||||||
this.NotFound("nsDomain", params.DomainId)
|
this.Data["keyword"] = params.Keyword
|
||||||
return
|
this.Data["routeId"] = params.RouteId
|
||||||
}
|
|
||||||
this.Data["domain"] = maps.Map{
|
|
||||||
"id": domain.Id,
|
|
||||||
"name": domain.Name,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 记录
|
// 记录
|
||||||
countResp, err := this.RPC().NSRecordRPC().CountAllEnabledNSRecords(this.AdminContext(), &pb.CountAllEnabledNSRecordsRequest{
|
countResp, err := this.RPC().NSRecordRPC().CountAllEnabledNSRecords(this.AdminContext(), &pb.CountAllEnabledNSRecordsRequest{
|
||||||
|
|||||||
80
internal/web/actions/default/ns/domains/tsig.go
Normal file
80
internal/web/actions/default/ns/domains/tsig.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package domains
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/domainutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TsigAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TsigAction) Init() {
|
||||||
|
this.Nav("", "", "tsig")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TsigAction) RunGet(params struct {
|
||||||
|
DomainId int64
|
||||||
|
}) {
|
||||||
|
// 初始化域名信息
|
||||||
|
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TSIG信息
|
||||||
|
tsigResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomainTSIG(this.AdminContext(), &pb.FindEnabledNSDomainTSIGRequest{NsDomainId: params.DomainId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var tsigJSON = tsigResp.TsigJSON
|
||||||
|
|
||||||
|
var tsigConfig = &dnsconfigs.TSIGConfig{}
|
||||||
|
if len(tsigJSON) > 0 {
|
||||||
|
err = json.Unmarshal(tsigJSON, tsigConfig)
|
||||||
|
if err != nil {
|
||||||
|
// 只是提示错误,仍然允许用户修改
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Data["tsig"] = tsigConfig
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TsigAction) RunPost(params struct {
|
||||||
|
DomainId int64
|
||||||
|
IsOn bool
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("修改DNS域名 %d 的TSIG配置", params.DomainId)
|
||||||
|
|
||||||
|
var tsigConfig = &dnsconfigs.TSIGConfig{
|
||||||
|
IsOn: params.IsOn,
|
||||||
|
}
|
||||||
|
tsigJSON, err := json.Marshal(tsigConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = this.RPC().NSDomainRPC().UpdateNSDomainTSIG(this.AdminContext(), &pb.UpdateNSDomainTSIGRequest{
|
||||||
|
NsDomainId: params.DomainId,
|
||||||
|
TsigJSON: tsigJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ package domains
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/domainutils"
|
||||||
"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"
|
||||||
@@ -20,6 +21,15 @@ func (this *UpdateAction) Init() {
|
|||||||
func (this *UpdateAction) RunGet(params struct {
|
func (this *UpdateAction) RunGet(params struct {
|
||||||
DomainId int64
|
DomainId int64
|
||||||
}) {
|
}) {
|
||||||
|
// 初始化域名信息
|
||||||
|
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var countRecords = this.Data.GetMap("domain").GetInt64("countRecords")
|
||||||
|
var countKeys = this.Data.GetMap("domain").GetInt64("countKeys")
|
||||||
|
|
||||||
// 域名信息
|
// 域名信息
|
||||||
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -44,11 +54,13 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.Data["domain"] = maps.Map{
|
this.Data["domain"] = maps.Map{
|
||||||
"id": domain.Id,
|
"id": domain.Id,
|
||||||
"name": domain.Name,
|
"name": domain.Name,
|
||||||
"isOn": domain.IsOn,
|
"isOn": domain.IsOn,
|
||||||
"clusterId": clusterId,
|
"clusterId": clusterId,
|
||||||
"userId": userId,
|
"userId": userId,
|
||||||
|
"countRecords": countRecords,
|
||||||
|
"countKeys": countKeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package ns
|
|||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
"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/records"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/records"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/iwind/TeaGo"
|
"github.com/iwind/TeaGo"
|
||||||
@@ -22,6 +23,15 @@ func init() {
|
|||||||
Post("/delete", new(domains.DeleteAction)).
|
Post("/delete", new(domains.DeleteAction)).
|
||||||
Get("/domain", new(domains.DomainAction)).
|
Get("/domain", new(domains.DomainAction)).
|
||||||
GetPost("/update", new(domains.UpdateAction)).
|
GetPost("/update", new(domains.UpdateAction)).
|
||||||
|
GetPost("/tsig", new(domains.TsigAction)).
|
||||||
|
|
||||||
|
// 域名密钥
|
||||||
|
Prefix("/ns/domains/keys").
|
||||||
|
Get("", new(keys.IndexAction)).
|
||||||
|
GetPost("/createPopup", new(keys.CreatePopupAction)).
|
||||||
|
GetPost("/updatePopup", new(keys.UpdatePopupAction)).
|
||||||
|
Post("/delete", new(keys.DeleteAction)).
|
||||||
|
Post("/generateSecret", new(keys.GenerateSecretAction)).
|
||||||
|
|
||||||
// 记录相关
|
// 记录相关
|
||||||
Prefix("/ns/domains/records").
|
Prefix("/ns/domains/records").
|
||||||
|
|||||||
179
internal/web/actions/default/servers/accesslogs/createPopup.go
Normal file
179
internal/web/actions/default/servers/accesslogs/createPopup.go
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package ipbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreatePopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||||
|
this.Data["types"] = serverconfigs.FindAllAccessLogStorageTypes()
|
||||||
|
this.Data["syslogPriorities"] = serverconfigs.AccessLogSyslogStoragePriorities
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunPost(params struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
|
||||||
|
// file
|
||||||
|
FilePath string
|
||||||
|
FileAutoCreate bool
|
||||||
|
|
||||||
|
// es
|
||||||
|
EsEndpoint string
|
||||||
|
EsIndex string
|
||||||
|
EsMappingType string
|
||||||
|
EsUsername string
|
||||||
|
EsPassword string
|
||||||
|
|
||||||
|
// mysql
|
||||||
|
MysqlHost string
|
||||||
|
MysqlPort int
|
||||||
|
MysqlUsername string
|
||||||
|
MysqlPassword string
|
||||||
|
MysqlDatabase string
|
||||||
|
MysqlTable string
|
||||||
|
MysqlLogField string
|
||||||
|
|
||||||
|
// tcp
|
||||||
|
TcpNetwork string
|
||||||
|
TcpAddr string
|
||||||
|
|
||||||
|
// syslog
|
||||||
|
SyslogProtocol string
|
||||||
|
SyslogServerAddr string
|
||||||
|
SyslogServerPort int
|
||||||
|
SyslogSocket string
|
||||||
|
SyslogTag string
|
||||||
|
SyslogPriority int
|
||||||
|
|
||||||
|
// command
|
||||||
|
CommandCommand string
|
||||||
|
CommandArgs string
|
||||||
|
CommandDir string
|
||||||
|
|
||||||
|
IsPublic bool
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
var policyId int64 = 0
|
||||||
|
defer func() {
|
||||||
|
this.CreateLogInfo("创建访问日志策略 %d", policyId)
|
||||||
|
}()
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("name", params.Name).
|
||||||
|
Require("请输入日志策略的名称").
|
||||||
|
Field("type", params.Type).
|
||||||
|
Require("请选择存储类型")
|
||||||
|
|
||||||
|
var options interface{} = nil
|
||||||
|
switch params.Type {
|
||||||
|
case serverconfigs.AccessLogStorageTypeFile:
|
||||||
|
params.Must.
|
||||||
|
Field("filePath", params.FilePath).
|
||||||
|
Require("请输入日志文件路径")
|
||||||
|
|
||||||
|
storage := new(serverconfigs.AccessLogFileStorageConfig)
|
||||||
|
storage.Path = params.FilePath
|
||||||
|
storage.AutoCreate = params.FileAutoCreate
|
||||||
|
options = storage
|
||||||
|
case serverconfigs.AccessLogStorageTypeES:
|
||||||
|
params.Must.
|
||||||
|
Field("esEndpoint", params.EsEndpoint).
|
||||||
|
Require("请输入Endpoint").
|
||||||
|
Field("esIndex", params.EsIndex).
|
||||||
|
Require("请输入Index名称").
|
||||||
|
Field("esMappingType", params.EsMappingType).
|
||||||
|
Require("请输入Mapping名称")
|
||||||
|
|
||||||
|
storage := new(serverconfigs.AccessLogESStorageConfig)
|
||||||
|
storage.Endpoint = params.EsEndpoint
|
||||||
|
storage.Index = params.EsIndex
|
||||||
|
storage.MappingType = params.EsMappingType
|
||||||
|
storage.Username = params.EsUsername
|
||||||
|
storage.Password = params.EsPassword
|
||||||
|
options = storage
|
||||||
|
case serverconfigs.AccessLogStorageTypeTCP:
|
||||||
|
params.Must.
|
||||||
|
Field("tcpNetwork", params.TcpNetwork).
|
||||||
|
Require("请选择网络协议").
|
||||||
|
Field("tcpAddr", params.TcpAddr).
|
||||||
|
Require("请输入网络地址")
|
||||||
|
|
||||||
|
storage := new(serverconfigs.AccessLogTCPStorageConfig)
|
||||||
|
storage.Network = params.TcpNetwork
|
||||||
|
storage.Addr = params.TcpAddr
|
||||||
|
options = storage
|
||||||
|
case serverconfigs.AccessLogStorageTypeSyslog:
|
||||||
|
switch params.SyslogProtocol {
|
||||||
|
case serverconfigs.AccessLogSyslogStorageProtocolTCP, serverconfigs.AccessLogSyslogStorageProtocolUDP:
|
||||||
|
params.Must.
|
||||||
|
Field("syslogServerAddr", params.SyslogServerAddr).
|
||||||
|
Require("请输入网络地址")
|
||||||
|
case serverconfigs.AccessLogSyslogStorageProtocolSocket:
|
||||||
|
params.Must.
|
||||||
|
Field("syslogSocket", params.SyslogSocket).
|
||||||
|
Require("请输入Socket路径")
|
||||||
|
}
|
||||||
|
|
||||||
|
storage := new(serverconfigs.AccessLogSyslogStorageConfig)
|
||||||
|
storage.Protocol = params.SyslogProtocol
|
||||||
|
storage.ServerAddr = params.SyslogServerAddr
|
||||||
|
storage.ServerPort = params.SyslogServerPort
|
||||||
|
storage.Socket = params.SyslogSocket
|
||||||
|
storage.Tag = params.SyslogTag
|
||||||
|
storage.Priority = params.SyslogPriority
|
||||||
|
options = storage
|
||||||
|
case serverconfigs.AccessLogStorageTypeCommand:
|
||||||
|
params.Must.
|
||||||
|
Field("commandCommand", params.CommandCommand).
|
||||||
|
Require("请输入可执行命令")
|
||||||
|
|
||||||
|
storage := new(serverconfigs.AccessLogCommandStorageConfig)
|
||||||
|
storage.Command = params.CommandCommand
|
||||||
|
storage.Args = cmd.ParseArgs(params.CommandArgs)
|
||||||
|
storage.Dir = params.CommandDir
|
||||||
|
options = storage
|
||||||
|
}
|
||||||
|
|
||||||
|
if options == nil {
|
||||||
|
this.Fail("找不到选择的存储类型")
|
||||||
|
}
|
||||||
|
|
||||||
|
optionsJSON, err := json.Marshal(options)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
createResp, err := this.RPC().HTTPAccessLogPolicyRPC().CreateHTTPAccessLogPolicy(this.AdminContext(), &pb.CreateHTTPAccessLogPolicyRequest{
|
||||||
|
Name: params.Name,
|
||||||
|
Type: params.Type,
|
||||||
|
OptionsJSON: optionsJSON,
|
||||||
|
CondsJSON: nil, // TODO
|
||||||
|
IsPublic: params.IsPublic,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
policyId = createResp.HttpAccessLogPolicyId
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
26
internal/web/actions/default/servers/accesslogs/delete.go
Normal file
26
internal/web/actions/default/servers/accesslogs/delete.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DeleteAction) RunPost(params struct {
|
||||||
|
PolicyId int64
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("删除访问日志策略 %d", params.PolicyId)
|
||||||
|
|
||||||
|
_, err := this.RPC().HTTPAccessLogPolicyRPC().DeleteHTTPAccessLogPolicy(this.AdminContext(), &pb.DeleteHTTPAccessLogPolicyRequest{HttpAccessLogPolicyId: params.PolicyId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
57
internal/web/actions/default/servers/accesslogs/index.go
Normal file
57
internal/web/actions/default/servers/accesslogs/index.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package ipbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "index")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct{}) {
|
||||||
|
countResp, err := this.RPC().HTTPAccessLogPolicyRPC().CountAllEnabledHTTPAccessLogPolicies(this.AdminContext(), &pb.CountAllEnabledHTTPAccessLogPoliciesRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
page := this.NewPage(countResp.Count)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
policiesResp, err := this.RPC().HTTPAccessLogPolicyRPC().ListEnabledHTTPAccessLogPolicies(this.AdminContext(), &pb.ListEnabledHTTPAccessLogPoliciesRequest{
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
var policyMaps = []maps.Map{}
|
||||||
|
for _, policy := range policiesResp.HttpAccessLogPolicies {
|
||||||
|
var optionsMap = maps.Map{}
|
||||||
|
if len(policy.OptionsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(policy.OptionsJSON, &optionsMap)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
policyMaps = append(policyMaps, maps.Map{
|
||||||
|
"id": policy.Id,
|
||||||
|
"name": policy.Name,
|
||||||
|
"type": policy.Type,
|
||||||
|
"typeName": serverconfigs.FindAccessLogStorageTypeName(policy.Type),
|
||||||
|
"isOn": policy.IsOn,
|
||||||
|
"isPublic": policy.IsPublic,
|
||||||
|
"options": optionsMap,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["policies"] = policyMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
26
internal/web/actions/default/servers/accesslogs/init.go
Normal file
26
internal/web/actions/default/servers/accesslogs/init.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package ipbox
|
||||||
|
|
||||||
|
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)).
|
||||||
|
Prefix("/servers/accesslogs").
|
||||||
|
Data("teaMenu", "servers").
|
||||||
|
Data("teaSubMenu", "accesslog").
|
||||||
|
Get("", new(IndexAction)).
|
||||||
|
GetPost("/createPopup", new(CreatePopupAction)).
|
||||||
|
Get("/policy", new(PolicyAction)).
|
||||||
|
GetPost("/test", new(TestAction)).
|
||||||
|
GetPost("/update", new(UpdateAction)).
|
||||||
|
Post("/delete", new(DeleteAction)).
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
36
internal/web/actions/default/servers/accesslogs/policy.go
Normal file
36
internal/web/actions/default/servers/accesslogs/policy.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package ipbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/accesslogs/policyutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PolicyAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *PolicyAction) Init() {
|
||||||
|
this.Nav("", "", "policy")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *PolicyAction) RunGet(params struct {
|
||||||
|
PolicyId int64
|
||||||
|
}) {
|
||||||
|
err := policyutils.InitPolicy(this.Parent(), params.PolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var policyMap = this.Data.GetMap("policy")
|
||||||
|
if policyMap.GetString("type") == serverconfigs.AccessLogStorageTypeSyslog {
|
||||||
|
this.Data["syslogPriorityName"] = serverconfigs.FindAccessLogSyslogStoragePriorityName(policyMap.GetMap("options").GetInt("priority"))
|
||||||
|
} else {
|
||||||
|
this.Data["syslogPriorityName"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package policyutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitPolicy 初始化访问日志策略
|
||||||
|
func InitPolicy(parent *actionutils.ParentAction, policyId int64) error {
|
||||||
|
rpcClient, err := rpc.SharedRPC()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
policyResp, err := rpcClient.HTTPAccessLogPolicyRPC().FindEnabledHTTPAccessLogPolicy(parent.AdminContext(), &pb.FindEnabledHTTPAccessLogPolicyRequest{HttpAccessLogPolicyId: policyId})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var policy = policyResp.HttpAccessLogPolicy
|
||||||
|
if policy == nil {
|
||||||
|
return errors.New("can not find policy '" + types.String(policyId) + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = maps.Map{}
|
||||||
|
if len(policy.OptionsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(policy.OptionsJSON, &options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.Data["policy"] = maps.Map{
|
||||||
|
"id": policy.Id,
|
||||||
|
"name": policy.Name,
|
||||||
|
"type": policy.Type,
|
||||||
|
"typeName": serverconfigs.FindAccessLogStorageTypeName(policy.Type),
|
||||||
|
"isOn": policy.IsOn,
|
||||||
|
"isPublic": policy.IsPublic,
|
||||||
|
"options": options,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
57
internal/web/actions/default/servers/accesslogs/test.go
Normal file
57
internal/web/actions/default/servers/accesslogs/test.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package ipbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/accesslogs/policyutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TestAction) Init() {
|
||||||
|
this.Nav("", "", "test")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TestAction) RunGet(params struct {
|
||||||
|
PolicyId int64
|
||||||
|
}) {
|
||||||
|
err := policyutils.InitPolicy(this.Parent(), params.PolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TestAction) RunPost(params struct {
|
||||||
|
PolicyId int64
|
||||||
|
BodyJSON []byte
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("测试向访问日志策略 %d 写入数据", params.PolicyId)
|
||||||
|
|
||||||
|
var accessLog = &pb.HTTPAccessLog{}
|
||||||
|
err := json.Unmarshal(params.BodyJSON, accessLog)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("发送内容不是有效的JSON:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = this.RPC().HTTPAccessLogPolicyRPC().WriteHTTPAccessLogPolicy(this.AdminContext(), &pb.WriteHTTPAccessLogPolicyRequest{
|
||||||
|
HttpAccessLogPolicyId: params.PolicyId,
|
||||||
|
HttpAccessLog: accessLog,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("发送失败:" + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
195
internal/web/actions/default/servers/accesslogs/update.go
Normal file
195
internal/web/actions/default/servers/accesslogs/update.go
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package ipbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/accesslogs/policyutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAction) Init() {
|
||||||
|
this.Nav("", "", "update")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAction) RunGet(params struct {
|
||||||
|
PolicyId int64
|
||||||
|
}) {
|
||||||
|
err := policyutils.InitPolicy(this.Parent(), params.PolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["types"] = serverconfigs.FindAllAccessLogStorageTypes()
|
||||||
|
this.Data["syslogPriorities"] = serverconfigs.AccessLogSyslogStoragePriorities
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAction) RunPost(params struct {
|
||||||
|
PolicyId int64
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// file
|
||||||
|
FilePath string
|
||||||
|
FileAutoCreate bool
|
||||||
|
|
||||||
|
// es
|
||||||
|
EsEndpoint string
|
||||||
|
EsIndex string
|
||||||
|
EsMappingType string
|
||||||
|
EsUsername string
|
||||||
|
EsPassword string
|
||||||
|
|
||||||
|
// mysql
|
||||||
|
MysqlHost string
|
||||||
|
MysqlPort int
|
||||||
|
MysqlUsername string
|
||||||
|
MysqlPassword string
|
||||||
|
MysqlDatabase string
|
||||||
|
MysqlTable string
|
||||||
|
MysqlLogField string
|
||||||
|
|
||||||
|
// tcp
|
||||||
|
TcpNetwork string
|
||||||
|
TcpAddr string
|
||||||
|
|
||||||
|
// syslog
|
||||||
|
SyslogProtocol string
|
||||||
|
SyslogServerAddr string
|
||||||
|
SyslogServerPort int
|
||||||
|
SyslogSocket string
|
||||||
|
SyslogTag string
|
||||||
|
SyslogPriority int
|
||||||
|
|
||||||
|
// command
|
||||||
|
CommandCommand string
|
||||||
|
CommandArgs string
|
||||||
|
CommandDir string
|
||||||
|
|
||||||
|
IsOn bool
|
||||||
|
IsPublic bool
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("修改访问日志策略 %d", params.PolicyId)
|
||||||
|
|
||||||
|
policyResp, err := this.RPC().HTTPAccessLogPolicyRPC().FindEnabledHTTPAccessLogPolicy(this.AdminContext(), &pb.FindEnabledHTTPAccessLogPolicyRequest{HttpAccessLogPolicyId: params.PolicyId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var policy = policyResp.HttpAccessLogPolicy
|
||||||
|
if policy == nil {
|
||||||
|
this.Fail("找不到要修改的策略")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("name", params.Name).
|
||||||
|
Require("请输入日志策略的名称")
|
||||||
|
|
||||||
|
var options interface{} = nil
|
||||||
|
switch policy.Type {
|
||||||
|
case serverconfigs.AccessLogStorageTypeFile:
|
||||||
|
params.Must.
|
||||||
|
Field("filePath", params.FilePath).
|
||||||
|
Require("请输入日志文件路径")
|
||||||
|
|
||||||
|
storage := new(serverconfigs.AccessLogFileStorageConfig)
|
||||||
|
storage.Path = params.FilePath
|
||||||
|
storage.AutoCreate = params.FileAutoCreate
|
||||||
|
options = storage
|
||||||
|
case serverconfigs.AccessLogStorageTypeES:
|
||||||
|
params.Must.
|
||||||
|
Field("esEndpoint", params.EsEndpoint).
|
||||||
|
Require("请输入Endpoint").
|
||||||
|
Field("esIndex", params.EsIndex).
|
||||||
|
Require("请输入Index名称").
|
||||||
|
Field("esMappingType", params.EsMappingType).
|
||||||
|
Require("请输入Mapping名称")
|
||||||
|
|
||||||
|
storage := new(serverconfigs.AccessLogESStorageConfig)
|
||||||
|
storage.Endpoint = params.EsEndpoint
|
||||||
|
storage.Index = params.EsIndex
|
||||||
|
storage.MappingType = params.EsMappingType
|
||||||
|
storage.Username = params.EsUsername
|
||||||
|
storage.Password = params.EsPassword
|
||||||
|
options = storage
|
||||||
|
case serverconfigs.AccessLogStorageTypeTCP:
|
||||||
|
params.Must.
|
||||||
|
Field("tcpNetwork", params.TcpNetwork).
|
||||||
|
Require("请选择网络协议").
|
||||||
|
Field("tcpAddr", params.TcpAddr).
|
||||||
|
Require("请输入网络地址")
|
||||||
|
|
||||||
|
storage := new(serverconfigs.AccessLogTCPStorageConfig)
|
||||||
|
storage.Network = params.TcpNetwork
|
||||||
|
storage.Addr = params.TcpAddr
|
||||||
|
options = storage
|
||||||
|
case serverconfigs.AccessLogStorageTypeSyslog:
|
||||||
|
switch params.SyslogProtocol {
|
||||||
|
case serverconfigs.AccessLogSyslogStorageProtocolTCP, serverconfigs.AccessLogSyslogStorageProtocolUDP:
|
||||||
|
params.Must.
|
||||||
|
Field("syslogServerAddr", params.SyslogServerAddr).
|
||||||
|
Require("请输入网络地址")
|
||||||
|
case serverconfigs.AccessLogSyslogStorageProtocolSocket:
|
||||||
|
params.Must.
|
||||||
|
Field("syslogSocket", params.SyslogSocket).
|
||||||
|
Require("请输入Socket路径")
|
||||||
|
}
|
||||||
|
|
||||||
|
storage := new(serverconfigs.AccessLogSyslogStorageConfig)
|
||||||
|
storage.Protocol = params.SyslogProtocol
|
||||||
|
storage.ServerAddr = params.SyslogServerAddr
|
||||||
|
storage.ServerPort = params.SyslogServerPort
|
||||||
|
storage.Socket = params.SyslogSocket
|
||||||
|
storage.Tag = params.SyslogTag
|
||||||
|
storage.Priority = params.SyslogPriority
|
||||||
|
options = storage
|
||||||
|
case serverconfigs.AccessLogStorageTypeCommand:
|
||||||
|
params.Must.
|
||||||
|
Field("commandCommand", params.CommandCommand).
|
||||||
|
Require("请输入可执行命令")
|
||||||
|
|
||||||
|
storage := new(serverconfigs.AccessLogCommandStorageConfig)
|
||||||
|
storage.Command = params.CommandCommand
|
||||||
|
storage.Args = cmd.ParseArgs(params.CommandArgs)
|
||||||
|
storage.Dir = params.CommandDir
|
||||||
|
options = storage
|
||||||
|
}
|
||||||
|
|
||||||
|
if options == nil {
|
||||||
|
this.Fail("找不到选择的存储类型")
|
||||||
|
}
|
||||||
|
|
||||||
|
optionsJSON, err := json.Marshal(options)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = this.RPC().HTTPAccessLogPolicyRPC().UpdateHTTPAccessLogPolicy(this.AdminContext(), &pb.UpdateHTTPAccessLogPolicyRequest{
|
||||||
|
HttpAccessLogPolicyId: params.PolicyId,
|
||||||
|
Name: params.Name,
|
||||||
|
OptionsJSON: optionsJSON,
|
||||||
|
CondsJSON: nil, // TODO
|
||||||
|
IsOn: params.IsOn,
|
||||||
|
IsPublic: params.IsPublic,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -132,7 +132,7 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
case serverconfigs.ServerTypeTCPProxy:
|
case serverconfigs.ServerTypeTCPProxy:
|
||||||
// 在DEMO模式下不能创建
|
// 在DEMO模式下不能创建
|
||||||
if teaconst.IsDemo {
|
if teaconst.IsDemoMode {
|
||||||
this.Fail("DEMO模式下不能创建TCP反向代理")
|
this.Fail("DEMO模式下不能创建TCP反向代理")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
case serverconfigs.ServerTypeUDPProxy:
|
case serverconfigs.ServerTypeUDPProxy:
|
||||||
// 在DEMO模式下不能创建
|
// 在DEMO模式下不能创建
|
||||||
if teaconst.IsDemo {
|
if teaconst.IsDemoMode {
|
||||||
this.Fail("DEMO模式下不能创建UDP反向代理")
|
this.Fail("DEMO模式下不能创建UDP反向代理")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -274,7 +274,9 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
server := serverResp.Server
|
|
||||||
|
// 服务
|
||||||
|
var server = serverResp.Server
|
||||||
if server == nil {
|
if server == nil {
|
||||||
// 设置为已修复
|
// 设置为已修复
|
||||||
_, err = this.RPC().NodeLogRPC().FixNodeLog(this.AdminContext(), &pb.FixNodeLogRequest{NodeLogId: errorLog.Id})
|
_, err = this.RPC().NodeLogRPC().FixNodeLog(this.AdminContext(), &pb.FixNodeLogRequest{NodeLogId: errorLog.Id})
|
||||||
@@ -286,6 +288,24 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 节点
|
||||||
|
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: errorLog.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var node = nodeResp.Node
|
||||||
|
if node == nil || node.NodeCluster == nil {
|
||||||
|
// 设置为已修复
|
||||||
|
_, err = this.RPC().NodeLogRPC().FixNodeLog(this.AdminContext(), &pb.FixNodeLogRequest{NodeLogId: errorLog.Id})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
errorLogMaps = append(errorLogMaps, maps.Map{
|
errorLogMaps = append(errorLogMaps, maps.Map{
|
||||||
"id": errorLog.Id,
|
"id": errorLog.Id,
|
||||||
"description": errorLog.Description,
|
"description": errorLog.Description,
|
||||||
@@ -293,6 +313,9 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
"serverId": errorLog.ServerId,
|
"serverId": errorLog.ServerId,
|
||||||
"level": errorLog.Level,
|
"level": errorLog.Level,
|
||||||
"serverName": server.Name,
|
"serverName": server.Name,
|
||||||
|
"nodeId": node.Id,
|
||||||
|
"nodeName": node.Name,
|
||||||
|
"clusterId": node.NodeCluster.Id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.Data["errorLogs"] = errorLogMaps
|
this.Data["errorLogs"] = errorLogMaps
|
||||||
|
|||||||
@@ -25,14 +25,19 @@ func InitChart(parent *actionutils.ParentAction, chartId int64) (*pb.MetricChart
|
|||||||
if chart == nil {
|
if chart == nil {
|
||||||
return nil, errors.New("metric chart not found")
|
return nil, errors.New("metric chart not found")
|
||||||
}
|
}
|
||||||
|
if len(chart.IgnoredKeys) == 0 {
|
||||||
|
chart.IgnoredKeys = []string{}
|
||||||
|
}
|
||||||
parent.Data["chart"] = maps.Map{
|
parent.Data["chart"] = maps.Map{
|
||||||
"id": chart.Id,
|
"id": chart.Id,
|
||||||
"name": chart.Name,
|
"name": chart.Name,
|
||||||
"isOn": chart.IsOn,
|
"isOn": chart.IsOn,
|
||||||
"widthDiv": chart.WidthDiv,
|
"widthDiv": chart.WidthDiv,
|
||||||
"maxItems": chart.MaxItems,
|
"maxItems": chart.MaxItems,
|
||||||
"type": chart.Type,
|
"type": chart.Type,
|
||||||
"typeName": serverconfigs.FindMetricChartTypeName(chart.Type),
|
"typeName": serverconfigs.FindMetricChartTypeName(chart.Type),
|
||||||
|
"ignoreEmptyKeys": chart.IgnoreEmptyKeys,
|
||||||
|
"ignoredKeys": chart.IgnoredKeys,
|
||||||
}
|
}
|
||||||
return chart, nil
|
return chart, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,13 @@ func (this *CreatePopupAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *CreatePopupAction) RunPost(params struct {
|
func (this *CreatePopupAction) RunPost(params struct {
|
||||||
ItemId int64
|
ItemId int64
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
WidthDiv int32
|
WidthDiv int32
|
||||||
MaxItems int32
|
MaxItems int32
|
||||||
|
IgnoreEmptyKeys bool
|
||||||
|
IgnoredKeys []string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
@@ -48,12 +50,14 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
Require("请选择图表类型")
|
Require("请选择图表类型")
|
||||||
|
|
||||||
createResp, err := this.RPC().MetricChartRPC().CreateMetricChart(this.AdminContext(), &pb.CreateMetricChartRequest{
|
createResp, err := this.RPC().MetricChartRPC().CreateMetricChart(this.AdminContext(), &pb.CreateMetricChartRequest{
|
||||||
MetricItemId: params.ItemId,
|
MetricItemId: params.ItemId,
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
Type: params.Type,
|
Type: params.Type,
|
||||||
WidthDiv: params.WidthDiv,
|
WidthDiv: params.WidthDiv,
|
||||||
MaxItems: params.MaxItems,
|
MaxItems: params.MaxItems,
|
||||||
ParamsJSON: nil,
|
ParamsJSON: nil,
|
||||||
|
IgnoreEmptyKeys: params.IgnoreEmptyKeys,
|
||||||
|
IgnoredKeys: params.IgnoredKeys,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -40,12 +40,14 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *UpdateAction) RunPost(params struct {
|
func (this *UpdateAction) RunPost(params struct {
|
||||||
ChartId int64
|
ChartId int64
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
WidthDiv int32
|
WidthDiv int32
|
||||||
MaxItems int32
|
MaxItems int32
|
||||||
IsOn bool
|
IsOn bool
|
||||||
|
IgnoreEmptyKeys bool
|
||||||
|
IgnoredKeys []string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
@@ -59,13 +61,15 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
Require("请选择图表类型")
|
Require("请选择图表类型")
|
||||||
|
|
||||||
_, err := this.RPC().MetricChartRPC().UpdateMetricChart(this.AdminContext(), &pb.UpdateMetricChartRequest{
|
_, err := this.RPC().MetricChartRPC().UpdateMetricChart(this.AdminContext(), &pb.UpdateMetricChartRequest{
|
||||||
MetricChartId: params.ChartId,
|
MetricChartId: params.ChartId,
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
Type: params.Type,
|
Type: params.Type,
|
||||||
WidthDiv: params.WidthDiv,
|
WidthDiv: params.WidthDiv,
|
||||||
MaxItems: params.MaxItems,
|
MaxItems: params.MaxItems,
|
||||||
ParamsJSON: nil,
|
ParamsJSON: nil,
|
||||||
IsOn: params.IsOn,
|
IgnoreEmptyKeys: params.IgnoreEmptyKeys,
|
||||||
|
IgnoredKeys: params.IgnoredKeys,
|
||||||
|
IsOn: params.IsOn,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -31,22 +30,6 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.Data["webId"] = webConfig.Id
|
this.Data["webId"] = webConfig.Id
|
||||||
this.Data["accessLogConfig"] = webConfig.AccessLogRef
|
this.Data["accessLogConfig"] = webConfig.AccessLogRef
|
||||||
|
|
||||||
// 可选的缓存策略
|
|
||||||
policiesResp, err := this.RPC().HTTPAccessLogPolicyRPC().FindAllEnabledHTTPAccessLogPolicies(this.AdminContext(), &pb.FindAllEnabledHTTPAccessLogPoliciesRequest{})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
policyMaps := []maps.Map{}
|
|
||||||
for _, policy := range policiesResp.AccessLogPolicies {
|
|
||||||
policyMaps = append(policyMaps, maps.Map{
|
|
||||||
"id": policy.Id,
|
|
||||||
"name": policy.Name,
|
|
||||||
"isOn": policy.IsOn, // TODO 这里界面上显示是否开启状态
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["accessLogPolicies"] = policyMaps
|
|
||||||
|
|
||||||
// 通用变量
|
// 通用变量
|
||||||
this.Data["fields"] = serverconfigs.HTTPAccessLogFields
|
this.Data["fields"] = serverconfigs.HTTPAccessLogFields
|
||||||
this.Data["defaultFieldCodes"] = serverconfigs.HTTPAccessLogDefaultFieldsCodes
|
this.Data["defaultFieldCodes"] = serverconfigs.HTTPAccessLogDefaultFieldsCodes
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -28,22 +27,6 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.Data["webId"] = webConfig.Id
|
this.Data["webId"] = webConfig.Id
|
||||||
this.Data["accessLogConfig"] = webConfig.AccessLogRef
|
this.Data["accessLogConfig"] = webConfig.AccessLogRef
|
||||||
|
|
||||||
// 可选的缓存策略
|
|
||||||
policiesResp, err := this.RPC().HTTPAccessLogPolicyRPC().FindAllEnabledHTTPAccessLogPolicies(this.AdminContext(), &pb.FindAllEnabledHTTPAccessLogPoliciesRequest{})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
policyMaps := []maps.Map{}
|
|
||||||
for _, policy := range policiesResp.AccessLogPolicies {
|
|
||||||
policyMaps = append(policyMaps, maps.Map{
|
|
||||||
"id": policy.Id,
|
|
||||||
"name": policy.Name,
|
|
||||||
"isOn": policy.IsOn, // TODO 这里界面上显示是否开启状态
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["accessLogPolicies"] = policyMaps
|
|
||||||
|
|
||||||
// 通用变量
|
// 通用变量
|
||||||
this.Data["fields"] = serverconfigs.HTTPAccessLogFields
|
this.Data["fields"] = serverconfigs.HTTPAccessLogFields
|
||||||
this.Data["defaultFieldCodes"] = serverconfigs.HTTPAccessLogDefaultFieldsCodes
|
this.Data["defaultFieldCodes"] = serverconfigs.HTTPAccessLogDefaultFieldsCodes
|
||||||
|
|||||||
@@ -31,20 +31,20 @@ func (this *LogsAction) RunGet(params struct {
|
|||||||
this.Data["keyword"] = params.Keyword
|
this.Data["keyword"] = params.Keyword
|
||||||
this.Data["level"] = params.Level
|
this.Data["level"] = params.Level
|
||||||
|
|
||||||
apiNodeResp, err := this.RPC().APINodeRPC().FindEnabledAPINode(this.AdminContext(), &pb.FindEnabledAPINodeRequest{NodeId: params.NodeId})
|
authorityNodeResp, err := this.RPC().AuthorityNodeRPC().FindEnabledAuthorityNode(this.AdminContext(), &pb.FindEnabledAuthorityNodeRequest{NodeId: params.NodeId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
apiNode := apiNodeResp.Node
|
authorityNode := authorityNodeResp.Node
|
||||||
if apiNode == nil {
|
if authorityNode == nil {
|
||||||
this.NotFound("apiNode", params.NodeId)
|
this.NotFound("authorityNode", params.NodeId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
this.Data["node"] = maps.Map{
|
||||||
"id": apiNode.Id,
|
"id": authorityNode.Id,
|
||||||
"name": apiNode.Name,
|
"name": authorityNode.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||||
|
|||||||
@@ -31,20 +31,20 @@ func (this *LogsAction) RunGet(params struct {
|
|||||||
this.Data["keyword"] = params.Keyword
|
this.Data["keyword"] = params.Keyword
|
||||||
this.Data["level"] = params.Level
|
this.Data["level"] = params.Level
|
||||||
|
|
||||||
apiNodeResp, err := this.RPC().APINodeRPC().FindEnabledAPINode(this.AdminContext(), &pb.FindEnabledAPINodeRequest{NodeId: params.NodeId})
|
monitorNodeResp, err := this.RPC().MonitorNodeRPC().FindEnabledMonitorNode(this.AdminContext(), &pb.FindEnabledMonitorNodeRequest{NodeId: params.NodeId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
apiNode := apiNodeResp.Node
|
monitorNode := monitorNodeResp.Node
|
||||||
if apiNode == nil {
|
if monitorNode == nil {
|
||||||
this.NotFound("apiNode", params.NodeId)
|
this.NotFound("monitorNode", params.NodeId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
this.Data["node"] = maps.Map{
|
||||||
"id": apiNode.Id,
|
"id": monitorNode.Id,
|
||||||
"name": apiNode.Name,
|
"name": monitorNode.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ func (this *AdvancedHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNex
|
|||||||
if teaconst.IsPlus {
|
if teaconst.IsPlus {
|
||||||
tabbar.Add("监控节点", "", "/settings/monitorNodes", "", this.tab == "monitorNodes")
|
tabbar.Add("监控节点", "", "/settings/monitorNodes", "", this.tab == "monitorNodes")
|
||||||
}
|
}
|
||||||
tabbar.Add("企业版认证", "", "/settings/authority", "", this.tab == "authority")
|
if teaconst.BuildPlus {
|
||||||
|
tabbar.Add("企业版认证", "", "/settings/authority", "", this.tab == "authority")
|
||||||
|
}
|
||||||
|
|
||||||
//tabbar.Add("备份", "", "/settings/backup", "", this.tab == "backup")
|
//tabbar.Add("备份", "", "/settings/backup", "", this.tab == "backup")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,20 +31,20 @@ func (this *LogsAction) RunGet(params struct {
|
|||||||
this.Data["keyword"] = params.Keyword
|
this.Data["keyword"] = params.Keyword
|
||||||
this.Data["level"] = params.Level
|
this.Data["level"] = params.Level
|
||||||
|
|
||||||
apiNodeResp, err := this.RPC().APINodeRPC().FindEnabledAPINode(this.AdminContext(), &pb.FindEnabledAPINodeRequest{NodeId: params.NodeId})
|
userNodeResp, err := this.RPC().UserNodeRPC().FindEnabledUserNode(this.AdminContext(), &pb.FindEnabledUserNodeRequest{NodeId: params.NodeId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
apiNode := apiNodeResp.Node
|
userNode := userNodeResp.Node
|
||||||
if apiNode == nil {
|
if userNode == nil {
|
||||||
this.NotFound("apiNode", params.NodeId)
|
this.NotFound("userNode", params.NodeId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
this.Data["node"] = maps.Map{
|
||||||
"id": apiNode.Id,
|
"id": userNode.Id,
|
||||||
"name": apiNode.Name,
|
"name": userNode.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 认证拦截
|
// 认证拦截
|
||||||
@@ -21,12 +22,32 @@ func NewUserMustAuth(module string) *userMustAuth {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramName string) (goNext bool) {
|
func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramName string) (goNext bool) {
|
||||||
|
var action = actionPtr.Object()
|
||||||
|
|
||||||
|
// 恢复模式
|
||||||
if teaconst.IsRecoverMode {
|
if teaconst.IsRecoverMode {
|
||||||
actionPtr.Object().RedirectURL("/recover")
|
action.RedirectURL("/recover")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var action = actionPtr.Object()
|
// DEMO模式
|
||||||
|
if teaconst.IsDemoMode {
|
||||||
|
if action.Request.Method == http.MethodPost {
|
||||||
|
var actionName = action.Spec.ClassName[strings.LastIndex(action.Spec.ClassName, ".")+1:]
|
||||||
|
var denyPrefixes = []string{"Update", "Create", "Delete", "Truncate", "Clean", "Clear", "Reset", "Add", "Remove", "Sync"}
|
||||||
|
for _, prefix := range denyPrefixes {
|
||||||
|
if strings.HasPrefix(actionName, prefix) {
|
||||||
|
action.Fail(teaconst.ErrorDemoOperation)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Index(action.Spec.PkgPath, "settings") > 0 || strings.Index(action.Spec.PkgPath, "delete") > 0 || strings.Index(action.Spec.PkgPath, "update") > 0 {
|
||||||
|
action.Fail(teaconst.ErrorDemoOperation)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 安全相关
|
// 安全相关
|
||||||
securityConfig, _ := configloaders.LoadSecurityConfig()
|
securityConfig, _ := configloaders.LoadSecurityConfig()
|
||||||
@@ -114,7 +135,7 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
|
|||||||
action.Data["teaShowOpenSourceInfo"] = config.ShowOpenSourceInfo
|
action.Data["teaShowOpenSourceInfo"] = config.ShowOpenSourceInfo
|
||||||
action.Data["teaIsSuper"] = false
|
action.Data["teaIsSuper"] = false
|
||||||
action.Data["teaIsPlus"] = teaconst.IsPlus
|
action.Data["teaIsPlus"] = teaconst.IsPlus
|
||||||
action.Data["teaDemoEnabled"] = teaconst.IsDemo
|
action.Data["teaDemoEnabled"] = teaconst.IsDemoMode
|
||||||
action.Data["teaShowFinance"] = configloaders.ShowFinance()
|
action.Data["teaShowFinance"] = configloaders.ShowFinance()
|
||||||
if !action.Data.Has("teaSubMenu") {
|
if !action.Data.Has("teaSubMenu") {
|
||||||
action.Data["teaSubMenu"] = ""
|
action.Data["teaSubMenu"] = ""
|
||||||
@@ -173,6 +194,12 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
|||||||
"url": "/servers/components/waf",
|
"url": "/servers/components/waf",
|
||||||
"code": "waf",
|
"code": "waf",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "日志策略",
|
||||||
|
"url": "/servers/accesslogs",
|
||||||
|
"code": "accesslog",
|
||||||
|
"isOn": teaconst.IsPlus,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "IP名单",
|
"name": "IP名单",
|
||||||
"url": "/servers/iplists",
|
"url": "/servers/iplists",
|
||||||
@@ -236,7 +263,7 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
|||||||
{
|
{
|
||||||
"code": "ns",
|
"code": "ns",
|
||||||
"module": configloaders.AdminModuleCodeNS,
|
"module": configloaders.AdminModuleCodeNS,
|
||||||
"name": "域名服务",
|
"name": "自建DNS",
|
||||||
"subtitle": "域名列表",
|
"subtitle": "域名列表",
|
||||||
"icon": "cubes",
|
"icon": "cubes",
|
||||||
"isOn": teaconst.IsPlus,
|
"isOn": teaconst.IsPlus,
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import (
|
|||||||
|
|
||||||
// 服务相关
|
// 服务相关
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers"
|
||||||
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/accesslogs"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// 单个集群选择
|
||||||
Vue.component("cluster-selector", {
|
Vue.component("cluster-selector", {
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
let that = this
|
let that = this
|
||||||
|
|||||||
28
web/public/js/components/cluster/node-clusters-labels.js
Normal file
28
web/public/js/components/cluster/node-clusters-labels.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// 显示节点的多个集群
|
||||||
|
Vue.component("node-clusters-labels", {
|
||||||
|
props: ["v-primary-cluster", "v-secondary-clusters", "size"],
|
||||||
|
data: function () {
|
||||||
|
let cluster = this.vPrimaryCluster
|
||||||
|
let secondaryClusters = this.vSecondaryClusters
|
||||||
|
if (secondaryClusters == null) {
|
||||||
|
secondaryClusters = []
|
||||||
|
}
|
||||||
|
|
||||||
|
let labelSize = this.size
|
||||||
|
if (labelSize == null) {
|
||||||
|
labelSize = "small"
|
||||||
|
}
|
||||||
|
if (labelSize == "tiny") {
|
||||||
|
labelSize += " olive"
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
cluster: cluster,
|
||||||
|
secondaryClusters: secondaryClusters,
|
||||||
|
labelSize: labelSize
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<a v-if="cluster != null" :href="'/clusters/cluster?clusterId=' + cluster.id" class="ui label basic" :class="labelSize" title="主集群" style="margin-bottom: 0.3em;">{{cluster.name}}</a>
|
||||||
|
<a v-for="c in secondaryClusters" :href="'/clusters/cluster?clusterId=' + c.id" class="ui label basic" :class="labelSize" title="从集群" style="margin-bottom: 0.3em;"><span class="grey" style="text-decoration: none">{{c.name}}</span></a>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
98
web/public/js/components/cluster/node-clusters-selector.js
Normal file
98
web/public/js/components/cluster/node-clusters-selector.js
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
// 一个节点的多个集群选择器
|
||||||
|
Vue.component("node-clusters-selector", {
|
||||||
|
props: ["v-primary-cluster", "v-secondary-clusters"],
|
||||||
|
data: function () {
|
||||||
|
let primaryCluster = this.vPrimaryCluster
|
||||||
|
|
||||||
|
let secondaryClusters = this.vSecondaryClusters
|
||||||
|
if (secondaryClusters == null) {
|
||||||
|
secondaryClusters = []
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
primaryClusterId: (primaryCluster == null) ? 0 : primaryCluster.id,
|
||||||
|
secondaryClusterIds: secondaryClusters.map(function (v) {
|
||||||
|
return v.id
|
||||||
|
}),
|
||||||
|
|
||||||
|
primaryCluster: primaryCluster,
|
||||||
|
secondaryClusters: secondaryClusters
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addPrimary: function () {
|
||||||
|
let that = this
|
||||||
|
let selectedClusterIds = [this.primaryClusterId].concat(this.secondaryClusterIds)
|
||||||
|
teaweb.popup("/clusters/selectPopup?selectedClusterIds=" + selectedClusterIds.join(",") + "&mode=single", {
|
||||||
|
height: "38em",
|
||||||
|
width: "50em",
|
||||||
|
callback: function (resp) {
|
||||||
|
if (resp.data.cluster != null) {
|
||||||
|
that.primaryCluster = resp.data.cluster
|
||||||
|
that.primaryClusterId = that.primaryCluster.id
|
||||||
|
that.notifyChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
removePrimary: function () {
|
||||||
|
this.primaryClusterId = 0
|
||||||
|
this.primaryCluster = null
|
||||||
|
this.notifyChange()
|
||||||
|
},
|
||||||
|
addSecondary: function () {
|
||||||
|
let that = this
|
||||||
|
let selectedClusterIds = [this.primaryClusterId].concat(this.secondaryClusterIds)
|
||||||
|
teaweb.popup("/clusters/selectPopup?selectedClusterIds=" + selectedClusterIds.join(",") + "&mode=multiple", {
|
||||||
|
height: "38em",
|
||||||
|
width: "50em",
|
||||||
|
callback: function (resp) {
|
||||||
|
if (resp.data.cluster != null) {
|
||||||
|
that.secondaryClusterIds.push(resp.data.cluster.id)
|
||||||
|
that.secondaryClusters.push(resp.data.cluster)
|
||||||
|
that.notifyChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
removeSecondary: function (index) {
|
||||||
|
this.secondaryClusterIds.$remove(index)
|
||||||
|
this.secondaryClusters.$remove(index)
|
||||||
|
this.notifyChange()
|
||||||
|
},
|
||||||
|
notifyChange: function () {
|
||||||
|
this.$emit("change", {
|
||||||
|
clusterId: this.primaryClusterId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" name="primaryClusterId" :value="primaryClusterId"/>
|
||||||
|
<input type="hidden" name="secondaryClusterIds" :value="JSON.stringify(secondaryClusterIds)"/>
|
||||||
|
<table class="ui table">
|
||||||
|
<tr>
|
||||||
|
<td class="title">主集群</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="primaryCluster != null">
|
||||||
|
<div class="ui label basic small">{{primaryCluster.name}} <a href="" title="删除" @click.prevent="removePrimary"><i class="icon remove small"></i></a> </div>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 0.6em" v-if="primaryClusterId == 0">
|
||||||
|
<button class="ui button tiny" type="button" @click.prevent="addPrimary">+</button>
|
||||||
|
</div>
|
||||||
|
<p class="comment">多个集群配置有冲突时,优先使用主集群配置。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>从集群</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="secondaryClusters.length > 0">
|
||||||
|
<div class="ui label basic small" v-for="(cluster, index) in secondaryClusters"><span class="grey">{{cluster.name}}</span> <a href="" title="删除" @click.prevent="removeSecondary(index)"><i class="icon remove small"></i></a> </div>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 0.6em">
|
||||||
|
<button class="ui button tiny" type="button" @click.prevent="addSecondary">+</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
let sourceCodeBoxIndex = 0
|
let sourceCodeBoxIndex = 0
|
||||||
|
|
||||||
Vue.component("source-code-box", {
|
Vue.component("source-code-box", {
|
||||||
props: ["type", "id"],
|
props: ["name", "type", "id", "read-only"],
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
|
let readOnly = this.readOnly
|
||||||
|
if (typeof readOnly != "boolean") {
|
||||||
|
readOnly = true
|
||||||
|
}
|
||||||
|
console.log("readonly:", readOnly) // TODO
|
||||||
let box = document.getElementById("source-code-box-" + this.index)
|
let box = document.getElementById("source-code-box-" + this.index)
|
||||||
let valueBox = document.getElementById(this.valueBoxId)
|
let valueBox = document.getElementById(this.valueBoxId)
|
||||||
let value = ""
|
let value = ""
|
||||||
@@ -15,7 +20,7 @@ Vue.component("source-code-box", {
|
|||||||
theme: "idea",
|
theme: "idea",
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
value: "",
|
value: "",
|
||||||
readOnly: true,
|
readOnly: readOnly,
|
||||||
showCursorWhenSelecting: true,
|
showCursorWhenSelecting: true,
|
||||||
height: "auto",
|
height: "auto",
|
||||||
//scrollbarStyle: null,
|
//scrollbarStyle: null,
|
||||||
@@ -49,6 +54,6 @@ Vue.component("source-code-box", {
|
|||||||
},
|
},
|
||||||
template: `<div class="source-code-box">
|
template: `<div class="source-code-box">
|
||||||
<div style="display: none" :id="valueBoxId"><slot></slot></div>
|
<div style="display: none" :id="valueBoxId"><slot></slot></div>
|
||||||
<textarea :id="'source-code-box-' + index"></textarea>
|
<textarea :id="'source-code-box-' + index" :name="name"></textarea>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// 警告消息
|
// 警告消息
|
||||||
Vue.component("warning-message", {
|
Vue.component("warning-message", {
|
||||||
template: `<p class="ui message warning"><i class="icon warning circle"></i><slot></slot></p>`
|
template: `<div class="ui icon message warning"><i class="icon warning circle"></i><div class="content"><slot></slot></div></div>`
|
||||||
})
|
})
|
||||||
@@ -8,7 +8,7 @@ Vue.component("dns-route-selector", {
|
|||||||
return {
|
return {
|
||||||
routes: routes,
|
routes: routes,
|
||||||
routeCodes: routes.$map(function (k, v) {
|
routeCodes: routes.$map(function (k, v) {
|
||||||
return v.code
|
return v.code + "@" + v.domainId
|
||||||
}),
|
}),
|
||||||
isAdding: false,
|
isAdding: false,
|
||||||
routeCode: ""
|
routeCode: ""
|
||||||
@@ -31,7 +31,7 @@ Vue.component("dns-route-selector", {
|
|||||||
}
|
}
|
||||||
let that = this
|
let that = this
|
||||||
let route = this.vAllRoutes.$find(function (k, v) {
|
let route = this.vAllRoutes.$find(function (k, v) {
|
||||||
return v.code == that.routeCode
|
return v.code + "@" + v.domainId == that.routeCode
|
||||||
})
|
})
|
||||||
if (route == null) {
|
if (route == null) {
|
||||||
return
|
return
|
||||||
@@ -53,8 +53,8 @@ Vue.component("dns-route-selector", {
|
|||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="dnsRoutesJSON" :value="JSON.stringify(routeCodes)"/>
|
<input type="hidden" name="dnsRoutesJSON" :value="JSON.stringify(routeCodes)"/>
|
||||||
<div v-if="routes.length > 0">
|
<div v-if="routes.length > 0">
|
||||||
<tiny-basic-label v-for="route in routes" :key="route.code">
|
<tiny-basic-label v-for="route in routes" :key="route.code + '@' + route.domainId">
|
||||||
{{route.name}} <a href="" @click.prevent="remove(route)"><i class="icon remove"></i></a>
|
{{route.name}} <span class="grey small">({{route.domainName}})</span><a href="" @click.prevent="remove(route)"><i class="icon remove"></i></a>
|
||||||
</tiny-basic-label>
|
</tiny-basic-label>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +64,7 @@ Vue.component("dns-route-selector", {
|
|||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<select class="ui dropdown auto-width" v-model="routeCode">
|
<select class="ui dropdown auto-width" v-model="routeCode">
|
||||||
<option value="">[请选择]</option>
|
<option value="">[请选择]</option>
|
||||||
<option v-for="route in vAllRoutes" :value="route.code">{{route.name}}</option>
|
<option v-for="route in vAllRoutes" :value="route.code + '@' + route.domainId">{{route.name}}({{route.domainName}})</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ Vue.component("grant-selector", {
|
|||||||
// 创建授权
|
// 创建授权
|
||||||
create: function () {
|
create: function () {
|
||||||
teaweb.popup("/clusters/grants/createPopup", {
|
teaweb.popup("/clusters/grants/createPopup", {
|
||||||
height: "31em",
|
height: "26em",
|
||||||
callback: (resp) => {
|
callback: (resp) => {
|
||||||
this.grantId = resp.data.grant.id;
|
this.grantId = resp.data.grant.id;
|
||||||
if (this.grantId > 0) {
|
if (this.grantId > 0) {
|
||||||
@@ -40,7 +40,7 @@ Vue.component("grant-selector", {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
teaweb.popup("/clusters/grants/updatePopup?grantId=" + this.grant.id, {
|
teaweb.popup("/clusters/grants/updatePopup?grantId=" + this.grant.id, {
|
||||||
height: "31em",
|
height: "26em",
|
||||||
callback: (resp) => {
|
callback: (resp) => {
|
||||||
this.grant = resp.data.grant;
|
this.grant = resp.data.grant;
|
||||||
}
|
}
|
||||||
|
|||||||
18
web/public/js/components/iplist/ip-box.js
Normal file
18
web/public/js/components/iplist/ip-box.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
Vue.component("ip-box", {
|
||||||
|
props: [],
|
||||||
|
methods: {
|
||||||
|
popup: function () {
|
||||||
|
let e = this.$refs.container
|
||||||
|
let text = e.innerText
|
||||||
|
if (text == null) {
|
||||||
|
text = e.textContent
|
||||||
|
}
|
||||||
|
|
||||||
|
teaweb.popup("/servers/ipbox?ip=" + text, {
|
||||||
|
width: "50em",
|
||||||
|
height: "30em"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<span @click.prevent="popup()" ref="container"><slot></slot></span>`
|
||||||
|
})
|
||||||
@@ -34,5 +34,8 @@ Vue.component("ns-access-log-box", {
|
|||||||
},
|
},
|
||||||
template: `<div class="access-log-row" :style="{'color': (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) ? '#dc143c' : ''}" ref="box">
|
template: `<div class="access-log-row" :style="{'color': (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) ? '#dc143c' : ''}" ref="box">
|
||||||
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword> [{{accessLog.timeLocal}}] [{{accessLog.networking}}] <em>{{accessLog.questionType}} <keyword :v-word="vKeyword">{{accessLog.questionName}}</keyword></em> -> <em>{{accessLog.recordType}} <keyword :v-word="vKeyword">{{accessLog.recordValue}}</keyword></em><!-- <a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>-->
|
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword> [{{accessLog.timeLocal}}] [{{accessLog.networking}}] <em>{{accessLog.questionType}} <keyword :v-word="vKeyword">{{accessLog.questionName}}</keyword></em> -> <em>{{accessLog.recordType}} <keyword :v-word="vKeyword">{{accessLog.recordValue}}</keyword></em><!-- <a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>-->
|
||||||
|
<div v-if="accessLog.error != null && accessLog.error.length > 0">
|
||||||
|
<i class="icon warning circle"></i>错误:[{{accessLog.error}}]
|
||||||
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
@@ -49,7 +49,7 @@ Vue.component("http-access-log-box", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div :style="{'color': (accessLog.status >= 400) ? '#dc143c' : ''}" ref="box">
|
template: `<div :style="{'color': (accessLog.status >= 400) ? '#dc143c' : ''}" ref="box">
|
||||||
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword> [{{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>
|
<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>`
|
||||||
})
|
})
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
Vue.component("http-access-log-config-box", {
|
Vue.component("http-access-log-config-box", {
|
||||||
props: ["v-access-log-config", "v-fields", "v-default-field-codes", "v-access-log-policies", "v-is-location"],
|
props: ["v-access-log-config", "v-fields", "v-default-field-codes", "v-is-location"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let that = this
|
let that = this
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
that.changeFields()
|
that.changeFields()
|
||||||
that.changePolicy()
|
|
||||||
}, 100)
|
}, 100)
|
||||||
|
|
||||||
let accessLog = {
|
let accessLog = {
|
||||||
@@ -19,9 +18,6 @@ Vue.component("http-access-log-config-box", {
|
|||||||
status4: true,
|
status4: true,
|
||||||
status5: true,
|
status5: true,
|
||||||
|
|
||||||
storageOnly: false,
|
|
||||||
storagePolicies: [],
|
|
||||||
|
|
||||||
firewallOnly: false
|
firewallOnly: false
|
||||||
}
|
}
|
||||||
if (this.vAccessLogConfig != null) {
|
if (this.vAccessLogConfig != null) {
|
||||||
@@ -35,9 +31,6 @@ Vue.component("http-access-log-config-box", {
|
|||||||
v.isChecked = accessLog.fields.$contains(v.code)
|
v.isChecked = accessLog.fields.$contains(v.code)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.vAccessLogPolicies.forEach(function (v) {
|
|
||||||
v.isChecked = accessLog.storagePolicies.$contains(v.id)
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accessLog: accessLog
|
accessLog: accessLog
|
||||||
@@ -50,13 +43,6 @@ Vue.component("http-access-log-config-box", {
|
|||||||
}).map(function (v) {
|
}).map(function (v) {
|
||||||
return v.code
|
return v.code
|
||||||
})
|
})
|
||||||
},
|
|
||||||
changePolicy: function () {
|
|
||||||
this.accessLog.storagePolicies = this.vAccessLogPolicies.filter(function (v) {
|
|
||||||
return v.isChecked
|
|
||||||
}).map(function (v) {
|
|
||||||
return v.id
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
@@ -110,28 +96,6 @@ Vue.component("http-access-log-config-box", {
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-show="vAccessLogPolicies.length > 0">
|
|
||||||
<td>选择输出的日志策略</td>
|
|
||||||
<td>
|
|
||||||
<span class="disabled" v-if="vAccessLogPolicies.length == 0">暂时还没有缓存策略。</span>
|
|
||||||
<div v-if="vAccessLogPolicies.length > 0">
|
|
||||||
<div class="ui checkbox" v-for="policy in vAccessLogPolicies" style="width:10em;margin-bottom:0.8em">
|
|
||||||
<input type="checkbox" v-model="policy.isChecked" @change="changePolicy" />
|
|
||||||
<label>{{policy.name}}</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-show="vAccessLogPolicies.length > 0">
|
|
||||||
<td>是否只输出到日志策略</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui checkbox">
|
|
||||||
<input type="checkbox" v-model="accessLog.storageOnly"/>
|
|
||||||
<label></label>
|
|
||||||
</div>
|
|
||||||
<p class="comment">选中表示只输出日志到日志策略,而停止默认的日志存储。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ Vue.component("http-firewall-rules-box", {
|
|||||||
{{rule.checkpointOptions.period}}秒/{{rule.checkpointOptions.threshold}}请求
|
{{rule.checkpointOptions.period}}秒/{{rule.checkpointOptions.threshold}}请求
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
<span v-if="rule.paramFilters != null && rule.paramFilters.length > 0" v-for="paramFilter in rule.paramFilters"> | {{paramFilter.code}}</span> <var v-if="rule.value.length > 0">{{rule.operator}}</var> {{rule.value}}
|
<span v-if="rule.paramFilters != null && rule.paramFilters.length > 0" v-for="paramFilter in rule.paramFilters"> | {{paramFilter.code}}</span> <var>{{rule.operator}}</var> {{rule.value}}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<a href="" title="修改" @click.prevent="updateRule(index, rule)"><i class="icon pencil small"></i></a>
|
<a href="" title="修改" @click.prevent="updateRule(index, rule)"><i class="icon pencil small"></i></a>
|
||||||
|
|||||||
@@ -8,7 +8,16 @@ Vue.component("http-redirect-to-https-box", {
|
|||||||
isOn: false,
|
isOn: false,
|
||||||
host: "",
|
host: "",
|
||||||
port: 0,
|
port: 0,
|
||||||
status: 0
|
status: 0,
|
||||||
|
onlyDomains: [],
|
||||||
|
exceptDomains: []
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (redirectToHttpsConfig.onlyDomains == null) {
|
||||||
|
redirectToHttpsConfig.onlyDomains = []
|
||||||
|
}
|
||||||
|
if (redirectToHttpsConfig.exceptDomains == null) {
|
||||||
|
redirectToHttpsConfig.exceptDomains = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -40,6 +49,14 @@ Vue.component("http-redirect-to-https-box", {
|
|||||||
methods: {
|
methods: {
|
||||||
changeMoreOptions: function (isVisible) {
|
changeMoreOptions: function (isVisible) {
|
||||||
this.moreOptionsVisible = isVisible
|
this.moreOptionsVisible = isVisible
|
||||||
|
},
|
||||||
|
changeOnlyDomains: function (values) {
|
||||||
|
this.redirectToHttpsConfig.onlyDomains = values
|
||||||
|
this.$forceUpdate()
|
||||||
|
},
|
||||||
|
changeExceptDomains: function (values) {
|
||||||
|
this.redirectToHttpsConfig.exceptDomains = values
|
||||||
|
this.$forceUpdate()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
@@ -109,10 +126,10 @@ Vue.component("http-redirect-to-https-box", {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>域名或IP地址</td>
|
<td>跳转后域名或IP地址</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="host" v-model="redirectToHttpsConfig.host"/>
|
<input type="text" name="host" v-model="redirectToHttpsConfig.host"/>
|
||||||
<p class="comment">默认和用户正在访问的域名或IP地址一致。</p>
|
<p class="comment">默认和用户正在访问的域名或IP地址一致,不填写就表示使用当前的域名。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -122,6 +139,20 @@ Vue.component("http-redirect-to-https-box", {
|
|||||||
<p class="comment">默认端口为443。</p>
|
<p class="comment">默认端口为443。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>允许的域名</td>
|
||||||
|
<td>
|
||||||
|
<values-box :values="redirectToHttpsConfig.onlyDomains" @change="changeOnlyDomains"></values-box>
|
||||||
|
<p class="comment">如果填写了允许的域名,那么只有这些域名可以自动跳转。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>排除的域名</td>
|
||||||
|
<td>
|
||||||
|
<values-box :values="redirectToHttpsConfig.exceptDomains" @change="changeExceptDomains"></values-box>
|
||||||
|
<p class="comment">如果填写了排除的域名,那么这些域名将不跳转。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="margin"></div>
|
<div class="margin"></div>
|
||||||
|
|||||||
@@ -345,17 +345,19 @@ Vue.component("metric-chart", {
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
// IP相关操作
|
if (this.item.keys != null) {
|
||||||
if (this.item.keys != null && this.item.keys.$contains("${remoteAddr}")) {
|
// IP相关操作
|
||||||
let that = this
|
if (this.item.keys.$contains("${remoteAddr}")) {
|
||||||
chart.on("click", function (args) {
|
let that = this
|
||||||
let index = that.item.keys.$indexesOf("${remoteAddr}")[0]
|
chart.on("click", function (args) {
|
||||||
let value = that.stats[args.dataIndex].keys[index]
|
let index = that.item.keys.$indexesOf("${remoteAddr}")[0]
|
||||||
teaweb.popup("/servers/ipbox?ip=" + value, {
|
let value = that.stats[args.dataIndex].keys[index]
|
||||||
width: "50em",
|
teaweb.popup("/servers/ipbox?ip=" + value, {
|
||||||
height: "30em"
|
width: "50em",
|
||||||
|
height: "30em"
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderTable: function (chart) {
|
renderTable: function (chart) {
|
||||||
|
|||||||
@@ -132,7 +132,27 @@ window.teaweb = {
|
|||||||
return (Math.round(bytes * 100 / 1024 / 1024 / 1024 / 1024 / 1024) / 100) + "P";
|
return (Math.round(bytes * 100 / 1024 / 1024 / 1024 / 1024 / 1024) / 100) + "P";
|
||||||
},
|
},
|
||||||
formatNumber: function (x) {
|
formatNumber: function (x) {
|
||||||
return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ", ");
|
if (x == null) {
|
||||||
|
return "null"
|
||||||
|
}
|
||||||
|
let s = x.toString()
|
||||||
|
let dotIndex = s.indexOf(".")
|
||||||
|
if (dotIndex >= 0) {
|
||||||
|
return this.formatNumber(s.substring(0, dotIndex)) + "." + s.substring(dotIndex + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.length <= 3) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
let result = []
|
||||||
|
for (let i = 0; i < Math.floor(s.length / 3); i++) {
|
||||||
|
let start = s.length - (i + 1) * 3
|
||||||
|
result.push(s.substring(start, start + 3))
|
||||||
|
}
|
||||||
|
if (s.length % 3 != 0) {
|
||||||
|
result.push(s.substring(0, s.length % 3))
|
||||||
|
}
|
||||||
|
return result.reverse().join(", ")
|
||||||
},
|
},
|
||||||
formatCount: function (x) {
|
formatCount: function (x) {
|
||||||
let unit = ""
|
let unit = ""
|
||||||
@@ -195,6 +215,10 @@ window.teaweb = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
popup: function (url, options) {
|
popup: function (url, options) {
|
||||||
|
if (url != null && url.length > 0 && url.substring(0, 1) == '.') {
|
||||||
|
url = Tea.url(url)
|
||||||
|
}
|
||||||
|
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
@@ -293,6 +317,27 @@ window.teaweb = {
|
|||||||
|
|
||||||
Swal.fire(config);
|
Swal.fire(config);
|
||||||
},
|
},
|
||||||
|
toast: function (message, timeout, callback) {
|
||||||
|
if (timeout == null) {
|
||||||
|
timeout = 2000
|
||||||
|
}
|
||||||
|
var width = "20em";
|
||||||
|
if (message.length > 30) {
|
||||||
|
width = "30em";
|
||||||
|
}
|
||||||
|
Swal.fire({
|
||||||
|
text: message,
|
||||||
|
icon: "info",
|
||||||
|
width: width,
|
||||||
|
timer: timeout,
|
||||||
|
showConfirmButton: false,
|
||||||
|
onAfterClose: function () {
|
||||||
|
if (typeof callback == "function") {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
successToast: function (message, timeout, callback) {
|
successToast: function (message, timeout, callback) {
|
||||||
if (timeout == null) {
|
if (timeout == null) {
|
||||||
timeout = 2000
|
timeout = 2000
|
||||||
@@ -523,7 +568,8 @@ window.teaweb = {
|
|||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: "#9DD3E8"
|
color: "#9DD3E8"
|
||||||
},
|
},
|
||||||
areaStyle: {}
|
areaStyle: {},
|
||||||
|
smooth: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
animation: true
|
animation: true
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -440,6 +440,7 @@ body.expanded .main {
|
|||||||
|
|
||||||
.main-menu.theme1 {
|
.main-menu.theme1 {
|
||||||
background: #14539A !important;
|
background: #14539A !important;
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
background: #14539A !important;
|
background: #14539A !important;
|
||||||
}
|
}
|
||||||
@@ -447,6 +448,7 @@ body.expanded .main {
|
|||||||
|
|
||||||
.main-menu.theme2 {
|
.main-menu.theme2 {
|
||||||
background: #276AC6 !important;
|
background: #276AC6 !important;
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
background: #276AC6 !important;
|
background: #276AC6 !important;
|
||||||
}
|
}
|
||||||
@@ -454,6 +456,7 @@ body.expanded .main {
|
|||||||
|
|
||||||
.main-menu.theme3 {
|
.main-menu.theme3 {
|
||||||
background: #007D9C !important;
|
background: #007D9C !important;
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
background: #007D9C !important;
|
background: #007D9C !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,4 +39,7 @@ textarea::-webkit-scrollbar {
|
|||||||
select.dropdown {
|
select.dropdown {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
}
|
}
|
||||||
|
.message .icon.warning {
|
||||||
|
font-size: 2em!important;
|
||||||
|
}
|
||||||
/*# sourceMappingURL=@layout_override.css.map */
|
/*# sourceMappingURL=@layout_override.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["@layout_override.less"],"names":[],"mappings":"AACA,GAAG,OAAO,SAAU,MAAK,MAAM,QAAS,OAAM;AAAS,GAAG,OAAO,SAAU,MAAK,MAAM,QAAS,QAAO;EACrG,oCAAA;;AAGD,GAAG,OAAO,SAAU,MAAK,QAAS,OAAM;AAAS,GAAG,OAAO,SAAU,MAAK,QAAS,QAAO;EACzF,oCAAA;;AAGD,GAAG,MAAM;EACR,kCAAA;;AAID,IACC;EACC,2BAAA;;AAKF,KAAK;EACJ,sBAAA;;AAGD,KAAK,KAAK;EACT,yBAAA;;AAID,KACC,GAAE;AADH,KACY,GAAE;EACZ,6BAAA;EACA,0BAAA;EACA,2BAAA;;AAJF,KAOC,GAAE;EACD,WAAA;;AARF,KAWC,GAAE;EACD,UAAA;;AAZF,KAeC,GAAE;EACD,UAAA;;AAKF,QAAQ;EACP,qBAAA;;AAID,MAAM;EACL,uBAAA","file":"@layout_override.css"}
|
{"version":3,"sources":["@layout_override.less"],"names":[],"mappings":"AACA,GAAG,OAAO,SAAU,MAAK,MAAM,QAAS,OAAM;AAAS,GAAG,OAAO,SAAU,MAAK,MAAM,QAAS,QAAO;EACrG,oCAAA;;AAGD,GAAG,OAAO,SAAU,MAAK,QAAS,OAAM;AAAS,GAAG,OAAO,SAAU,MAAK,QAAS,QAAO;EACzF,oCAAA;;AAGD,GAAG,MAAM;EACR,kCAAA;;AAID,IACC;EACC,2BAAA;;AAKF,KAAK;EACJ,sBAAA;;AAGD,KAAK,KAAK;EACT,yBAAA;;AAID,KACC,GAAE;AADH,KACY,GAAE;EACZ,6BAAA;EACA,0BAAA;EACA,2BAAA;;AAJF,KAOC,GAAE;EACD,WAAA;;AARF,KAWC,GAAE;EACD,UAAA;;AAZF,KAeC,GAAE;EACD,UAAA;;AAKF,QAAQ;EACP,qBAAA;;AAID,MAAM;EACL,uBAAA;;AAID,QACC,MAAK;EACJ,wBAAA","file":"@layout_override.css"}
|
||||||
@@ -57,3 +57,10 @@ textarea::-webkit-scrollbar {
|
|||||||
select.dropdown {
|
select.dropdown {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// message
|
||||||
|
.message {
|
||||||
|
.icon.warning {
|
||||||
|
font-size: 2em!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="ui four columns grid">
|
<div class="ui four columns grid">
|
||||||
<div class="ui column">
|
<div class="ui column">
|
||||||
<h4>在线节点<link-icon :href="'/clusters/cluster/nodes?clusterId=' + clusterId"></link-icon></h4>
|
<h4>在线节点<link-icon :href="'/clusters/cluster/nodes?clusterId=' + clusterId"></link-icon></h4>
|
||||||
<div class="value"><span>{{board.countActiveNodes}}</span>个</div>
|
<div class="value"><span class="green">{{board.countActiveNodes}}</span>个</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui column">
|
<div class="ui column">
|
||||||
<h4>离线节点<link-icon :href="'/clusters/cluster/nodes?clusterId=' + clusterId"></link-icon></h4>
|
<h4>离线节点<link-icon :href="'/clusters/cluster/nodes?clusterId=' + clusterId"></link-icon></h4>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ Tea.context(function () {
|
|||||||
attackRatio = Math.round(stats[index].attackBytes * 10000 / stats[index].bytes) / 100
|
attackRatio = Math.round(stats[index].attackBytes * 10000 / stats[index].bytes) / 100
|
||||||
}
|
}
|
||||||
|
|
||||||
return stats[index].day + " " + stats[index].hour + "时<br/>总流量:" + teaweb.formatBytes(stats[index].bytes) + "<br/>缓存流量:" + teaweb.formatBytes(stats[index].cachedBytes) + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击流量:" + teaweb.formatBytes(stats[index].attackBytes) + "<br/>拦截比例:" + attackRatio + "%"
|
return stats[index].day + " " + stats[index].hour + "时<br/>总流量:" + teaweb.formatBytes(stats[index].bytes) + "<br/>缓存流量:" + teaweb.formatBytes(stats[index].cachedBytes) + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击流量:" + teaweb.formatBytes(stats[index].attackBytes) + "<br/>拦截比例:" + attackRatio + "%"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,8 @@ Tea.context(function () {
|
|||||||
},
|
},
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: "#9DD3E8"
|
color: "#9DD3E8"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "缓存流量",
|
name: "缓存流量",
|
||||||
@@ -118,7 +119,8 @@ Tea.context(function () {
|
|||||||
},
|
},
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: "#61A0A8"
|
color: "#61A0A8"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "攻击流量",
|
name: "攻击流量",
|
||||||
@@ -128,7 +130,11 @@ Tea.context(function () {
|
|||||||
}),
|
}),
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: "#F39494"
|
color: "#F39494"
|
||||||
}
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: "#F39494"
|
||||||
|
},
|
||||||
|
smooth: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
legend: {
|
legend: {
|
||||||
@@ -241,7 +247,8 @@ Tea.context(function () {
|
|||||||
},
|
},
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: "#9DD3E8"
|
color: "#9DD3E8"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "缓存请求数",
|
name: "缓存请求数",
|
||||||
@@ -254,7 +261,8 @@ Tea.context(function () {
|
|||||||
},
|
},
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: "#61A0A8"
|
color: "#61A0A8"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "攻击请求数",
|
name: "攻击请求数",
|
||||||
@@ -265,9 +273,10 @@ Tea.context(function () {
|
|||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: "#F39494"
|
color: "#F39494"
|
||||||
},
|
},
|
||||||
lineStyle: {
|
areaStyle: {
|
||||||
color: "#F39494"
|
color: "#F39494"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
legend: {
|
legend: {
|
||||||
@@ -323,7 +332,10 @@ Tea.context(function () {
|
|||||||
value: function (v) {
|
value: function (v) {
|
||||||
return v.countRequests / axis.divider;
|
return v.countRequests / axis.divider;
|
||||||
},
|
},
|
||||||
axis: axis
|
axis: axis,
|
||||||
|
click: function (args, stats) {
|
||||||
|
window.location = "/servers/server?serverId=" + stats[args.dataIndex].serverId
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ Tea.context(function () {
|
|||||||
case "EMPTY_GRANT":
|
case "EMPTY_GRANT":
|
||||||
teaweb.warn("需要填写SSH登录信息", function () {
|
teaweb.warn("需要填写SSH登录信息", function () {
|
||||||
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
||||||
|
height: "30em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.reload()
|
teaweb.reload()
|
||||||
}
|
}
|
||||||
@@ -123,6 +124,7 @@ Tea.context(function () {
|
|||||||
case "SSH登录失败,请检查设置":
|
case "SSH登录失败,请检查设置":
|
||||||
teaweb.warn("需要填写SSH登录信息", function () {
|
teaweb.warn("需要填写SSH登录信息", function () {
|
||||||
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
||||||
|
height: "30em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.reload()
|
teaweb.reload()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<second-menu>
|
<second-menu>
|
||||||
<menu-item :href="'/clusters/cluster/nodes?clusterId=' + clusterId">节点列表</menu-item>
|
<menu-item :href="'/clusters/cluster/nodes?clusterId=' + clusterId">节点列表</menu-item>
|
||||||
<span class="item disabled">|</span>
|
<span class="item disabled">|</span>
|
||||||
<menu-item :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id" code="node"
|
<menu-item :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id" code="node"
|
||||||
v-if="!teaIsPlus">"{{node.name}}"节点详情</menu-item>
|
v-if="!teaIsPlus">"{{node.name}}"节点详情</menu-item>
|
||||||
@@ -7,6 +7,6 @@
|
|||||||
<menu-item :href="'/clusters/cluster/node/detail?clusterId=' + clusterId + '&nodeId=' + node.id" code="node" v-if="teaIsPlus">节点详情</menu-item>
|
<menu-item :href="'/clusters/cluster/node/detail?clusterId=' + clusterId + '&nodeId=' + node.id" code="node" v-if="teaIsPlus">节点详情</menu-item>
|
||||||
<menu-item :href="'/clusters/cluster/node/thresholds?clusterId=' + clusterId + '&nodeId=' + node.id" code="threshold" v-if="teaIsPlus">阈值设置</menu-item>
|
<menu-item :href="'/clusters/cluster/node/thresholds?clusterId=' + clusterId + '&nodeId=' + node.id" code="threshold" v-if="teaIsPlus">阈值设置</menu-item>
|
||||||
<menu-item :href="'/clusters/cluster/node/logs?clusterId=' + clusterId + '&nodeId=' + node.id" code="log">运行日志</menu-item>
|
<menu-item :href="'/clusters/cluster/node/logs?clusterId=' + clusterId + '&nodeId=' + node.id" code="log">运行日志</menu-item>
|
||||||
|
<menu-item :href="'/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" code="install">安装节点</menu-item>
|
||||||
<menu-item :href="'/clusters/cluster/node/update?clusterId=' + clusterId + '&nodeId=' + node.id" code="update">修改设置</menu-item>
|
<menu-item :href="'/clusters/cluster/node/update?clusterId=' + clusterId + '&nodeId=' + node.id" code="update">修改设置</menu-item>
|
||||||
<menu-item :href="'/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" code="install">安装节点</menu-item>
|
|
||||||
</second-menu>
|
</second-menu>
|
||||||
@@ -82,7 +82,7 @@ Tea.context(function () {
|
|||||||
attackRatio = Math.round(stats[index].attackBytes * 10000 / stats[index].bytes) / 100
|
attackRatio = Math.round(stats[index].attackBytes * 10000 / stats[index].bytes) / 100
|
||||||
}
|
}
|
||||||
|
|
||||||
return stats[index].day + " " + stats[index].hour + "时<br/>总流量:" + teaweb.formatBytes(stats[index].bytes) + "<br/>缓存流量:" + teaweb.formatBytes(stats[index].cachedBytes) + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击流量:" + teaweb.formatBytes(stats[index].attackBytes) + "<br/>拦截比例:" + attackRatio + "%"
|
return stats[index].day + " " + stats[index].hour + "时<br/>总流量:" + teaweb.formatBytes(stats[index].bytes) + "<br/>缓存流量:" + teaweb.formatBytes(stats[index].cachedBytes) + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击流量:" + teaweb.formatBytes(stats[index].attackBytes) + "<br/>拦截比例:" + attackRatio + "%"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +151,8 @@ Tea.context(function () {
|
|||||||
},
|
},
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: "#9DD3E8"
|
color: "#9DD3E8"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "缓存流量",
|
name: "缓存流量",
|
||||||
@@ -164,7 +165,8 @@ Tea.context(function () {
|
|||||||
},
|
},
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: "#61A0A8"
|
color: "#61A0A8"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "攻击流量",
|
name: "攻击流量",
|
||||||
@@ -175,9 +177,10 @@ Tea.context(function () {
|
|||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: "#F39494"
|
color: "#F39494"
|
||||||
},
|
},
|
||||||
lineStyle: {
|
areaStyle: {
|
||||||
color: "#F39494"
|
color: "#F39494"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
legend: {
|
legend: {
|
||||||
@@ -290,7 +293,8 @@ Tea.context(function () {
|
|||||||
},
|
},
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: "#9DD3E8"
|
color: "#9DD3E8"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "缓存请求数",
|
name: "缓存请求数",
|
||||||
@@ -303,7 +307,8 @@ Tea.context(function () {
|
|||||||
},
|
},
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: "#61A0A8"
|
color: "#61A0A8"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "攻击请求数",
|
name: "攻击请求数",
|
||||||
@@ -314,9 +319,10 @@ Tea.context(function () {
|
|||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: "#F39494"
|
color: "#F39494"
|
||||||
},
|
},
|
||||||
lineStyle: {
|
areaStyle: {
|
||||||
color: "#F39494"
|
color: "#F39494"
|
||||||
}
|
},
|
||||||
|
smooth: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
legend: {
|
legend: {
|
||||||
@@ -452,10 +458,13 @@ Tea.context(function () {
|
|||||||
this.cacheDirAvail = ""
|
this.cacheDirAvail = ""
|
||||||
this.cacheDirAvailWarning = false
|
this.cacheDirAvailWarning = false
|
||||||
if (this.cacheDirValues.length > 0) {
|
if (this.cacheDirValues.length > 0) {
|
||||||
this.cacheDirUsed = teaweb.formatBytes(this.cacheDirValues.$last().value.dirs[0].used)
|
let lastStat = this.cacheDirValues.$last()
|
||||||
this.cacheDirTotal = teaweb.formatBytes(this.cacheDirValues.$last().value.dirs[0].total)
|
if (lastStat.value != null && lastStat.value.dirs != null && lastStat.value.dirs.length > 0) {
|
||||||
this.cacheDirAvail = teaweb.formatBytes(this.cacheDirValues.$last().value.dirs[0].avail)
|
this.cacheDirUsed = teaweb.formatBytes(this.cacheDirValues.$last().value.dirs[0].used)
|
||||||
this.cacheDirAvailWarning = (this.cacheDirValues.$last().value.dirs[0].avail < 1024 * 1024 * 1024 * 10)
|
this.cacheDirTotal = teaweb.formatBytes(this.cacheDirValues.$last().value.dirs[0].total)
|
||||||
|
this.cacheDirAvail = teaweb.formatBytes(this.cacheDirValues.$last().value.dirs[0].avail)
|
||||||
|
this.cacheDirAvailWarning = (this.cacheDirValues.$last().value.dirs[0].avail < 1024 * 1024 * 1024 * 10)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.reloadCacheDirsChart = function () {
|
this.reloadCacheDirsChart = function () {
|
||||||
let axis = {unit: "%", divider: 1}
|
let axis = {unit: "%", divider: 1}
|
||||||
@@ -471,7 +480,7 @@ Tea.context(function () {
|
|||||||
return stats[args.dataIndex].time + "<br/>使用:" + teaweb.formatBytes(v.used) + "<br/>总量:" + teaweb.formatBytes(v.total) + "<br/>比例:" + (Math.ceil(v.used * 100 / v.total * 100) / 100) + "%"
|
return stats[args.dataIndex].time + "<br/>使用:" + teaweb.formatBytes(v.used) + "<br/>总量:" + teaweb.formatBytes(v.total) + "<br/>比例:" + (Math.ceil(v.used * 100 / v.total * 100) / 100) + "%"
|
||||||
},
|
},
|
||||||
value: function (v) {
|
value: function (v) {
|
||||||
if (v.value.dirs.length ==0) {
|
if (v.value == null || v.value.dirs == null || v.value.dirs.length == 0) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
v = v.value.dirs[0]
|
v = v.value.dirs[0]
|
||||||
|
|||||||
@@ -12,6 +12,12 @@
|
|||||||
<td>状态</td>
|
<td>状态</td>
|
||||||
<td><label-on :v-is-on="node.isOn"></label-on></td>
|
<td><label-on :v-is-on="node.isOn"></label-on></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>所属集群</td>
|
||||||
|
<td>
|
||||||
|
<node-clusters-labels :v-primary-cluster="node.cluster" :v-secondary-clusters="node.secondaryClusters"></node-clusters-labels>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>IP地址</td>
|
<td>IP地址</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -29,38 +35,34 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="dnsRoutes.length > 0 && dnsRoutes[0].name.length > 0">
|
<tr v-if="node.routes.length > 0">
|
||||||
<td>DNS线路</td>
|
<td>DNS线路</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="ui label tiny basic" v-for="route in dnsRoutes">{{route.name}}</span>
|
<span class="ui label tiny basic" v-for="route in node.routes">{{route.name}} <span class="grey small">({{route.domainName}})</span></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="dnsRecordName.length > 0 && dnsRecordValue.length > 0">
|
<tr v-if="node.records.length > 0">
|
||||||
<td>DNS记录</td>
|
<td>DNS记录</td>
|
||||||
<td>
|
<td>
|
||||||
<table class="ui table celled">
|
<table class="ui table celled">
|
||||||
<thead class="full-width">
|
<thead class="full-width">
|
||||||
<tr>
|
<tr>
|
||||||
<th>记录名</th>
|
<th>记录名</th>
|
||||||
<th>记录类型</th>
|
<th>记录类型</th>
|
||||||
<th>线路</th>
|
<th>线路</th>
|
||||||
<th>记录值</th>
|
<th>记录值</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody v-for="address in node.ipAddresses" v-if="address.canAccess">
|
|
||||||
<tr v-for="route in dnsRoutes">
|
<tr v-for="record in node.records">
|
||||||
<td>{{dnsRecordName}}</td>
|
<td>{{record.name}}</td>
|
||||||
<td>
|
<td>{{record.type}}</td>
|
||||||
<span v-if="address.ip.indexOf(':') > -1">AAAA</span>
|
<td>
|
||||||
<span v-else>A</span>
|
<span v-if="record.route.length > 0">{{record.route}}</span>
|
||||||
</td>
|
<span v-else class="disabled">默认</span>
|
||||||
<td>
|
</td>
|
||||||
<span v-if="route.name.length > 0">{{route.name}}</span>
|
<td>{{record.value}}</td>
|
||||||
<span v-else class="disabled">默认</span>
|
</tr>
|
||||||
</td>
|
|
||||||
<td>{{address.ip}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
<p class="comment">通过设置A记录可以将集群上的服务请求转发到不同线路的节点上。</p>
|
<p class="comment">通过设置A记录可以将集群上的服务请求转发到不同线路的节点上。</p>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -74,6 +74,6 @@ secret: "{{node.secret}}"</source-code-box>
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="ui message success">当前节点为已安装状态。</div>
|
<div class="ui message success">当前节点为已安装状态。</div>
|
||||||
<a href="" @click.prevent="updateNodeIsInstalled(false)">[修改为未安装状态]</a>
|
<a href="" @click.prevent="updateNodeIsInstalled(false)">[重新安装]</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,6 +60,7 @@ Tea.context(function () {
|
|||||||
case "EMPTY_GRANT":
|
case "EMPTY_GRANT":
|
||||||
teaweb.warn("需要填写SSH登录信息", function () {
|
teaweb.warn("需要填写SSH登录信息", function () {
|
||||||
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
||||||
|
height: "30em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
that.install()
|
that.install()
|
||||||
}
|
}
|
||||||
@@ -69,6 +70,7 @@ Tea.context(function () {
|
|||||||
case "SSH_LOGIN_FAILED":
|
case "SSH_LOGIN_FAILED":
|
||||||
teaweb.warn("SSH登录失败,请检查设置", function () {
|
teaweb.warn("SSH登录失败,请检查设置", function () {
|
||||||
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
||||||
|
height: "30em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
that.install()
|
that.install()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,12 @@
|
|||||||
<input type="text" name="name" maxlength="50" ref="focus" v-model="node.name"/>
|
<input type="text" name="name" maxlength="50" ref="focus" v-model="node.name"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>所属集群</td>
|
||||||
|
<td>
|
||||||
|
<node-clusters-selector :v-primary-cluster="node.primaryCluster" :v-secondary-clusters="node.secondaryClusters" @change="changeClusters"></node-clusters-selector>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>IP地址 *</td>
|
<td>IP地址 *</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -20,22 +26,13 @@
|
|||||||
<p class="comment">用于访问节点和域名解析等。</p>
|
<p class="comment">用于访问节点和域名解析等。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="allDNSRoutes.length > 0">
|
<tr v-if="allDNSRoutes.length > 0">
|
||||||
<td>DNS线路</td>
|
<td>DNS线路</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="hidden" name="dnsDomainId" :value="dnsDomainId"/>
|
|
||||||
<dns-route-selector :v-all-routes="allDNSRoutes" :v-routes="dnsRoutes"></dns-route-selector>
|
<dns-route-selector :v-all-routes="allDNSRoutes" :v-routes="dnsRoutes"></dns-route-selector>
|
||||||
<p class="comment">当前节点对应的DNS线路,可用线路是根据集群设置的域名获取的,注意DNS服务商可能对这些线路有其他限制。</p>
|
<p class="comment">当前节点对应的DNS线路,可用线路是根据集群设置的域名获取的,注意DNS服务商可能对这些线路有其他限制。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>所属集群</td>
|
|
||||||
<td>
|
|
||||||
<select class="ui dropdown" name="clusterId" style="width:10em" v-model="clusterId">
|
|
||||||
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>所属区域</td>
|
<td>所属区域</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -1,27 +1,32 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.clusterId = 0;
|
this.clusterId = 0
|
||||||
if (this.node.cluster != null && this.node.cluster.id > 0) {
|
if (this.node.cluster != null && this.node.cluster.id > 0) {
|
||||||
this.clusterId = this.node.cluster.id;
|
this.clusterId = this.node.cluster.id
|
||||||
}
|
}
|
||||||
|
|
||||||
this.success = NotifySuccess("保存成功", "/clusters/cluster/node?clusterId=" + this.clusterId + "&nodeId=" + this.node.id);
|
this.success = function () {
|
||||||
|
let that = this
|
||||||
|
teaweb.success("保存成功", function () {
|
||||||
|
window.location = "/clusters/cluster/node/detail?clusterId=" + that.clusterId + "&nodeId=" + that.node.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// IP地址相关
|
// IP地址相关
|
||||||
this.ipAddresses = this.node.ipAddresses;
|
this.ipAddresses = this.node.ipAddresses
|
||||||
|
|
||||||
// 认证相关
|
// 认证相关
|
||||||
this.grant = null;
|
this.grant = null
|
||||||
|
|
||||||
this.sshHost = "";
|
this.sshHost = ""
|
||||||
this.sshPort = "";
|
this.sshPort = ""
|
||||||
this.loginId = 0;
|
this.loginId = 0
|
||||||
if (this.node.login != null) {
|
if (this.node.login != null) {
|
||||||
this.loginId = this.node.login.id;
|
this.loginId = this.node.login.id
|
||||||
|
|
||||||
if (this.node.login.params != null) {
|
if (this.node.login.params != null) {
|
||||||
this.sshHost = this.node.login.params.host;
|
this.sshHost = this.node.login.params.host
|
||||||
if (this.node.login.params.port > 0) {
|
if (this.node.login.params.port > 0) {
|
||||||
this.sshPort = this.node.login.params.port;
|
this.sshPort = this.node.login.params.port
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +36,11 @@ Tea.context(function () {
|
|||||||
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
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
this.changeClusters = function (info) {
|
||||||
|
this.clusterId = info.clusterId
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -68,10 +68,13 @@
|
|||||||
<tr v-for="node in nodes">
|
<tr v-for="node in nodes">
|
||||||
<td>{{node.name}}
|
<td>{{node.name}}
|
||||||
<div style="margin-top: 0.5em" v-if="node.region != null">
|
<div style="margin-top: 0.5em" v-if="node.region != null">
|
||||||
<tiny-basic-label>区域:{{node.region.name}}</tiny-basic-label>
|
<tiny-basic-label class="olive">区域:{{node.region.name}}</tiny-basic-label>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 0.5em" v-if="node.group != null">
|
<div style="margin-top: 0.5em" v-if="node.group != null">
|
||||||
<tiny-basic-label>分组:{{node.group.name}}</tiny-basic-label>
|
<tiny-basic-label class="olive">分组:{{node.group.name}}</tiny-basic-label>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 0.5em">
|
||||||
|
<node-clusters-labels :v-primary-cluster="node.cluster" :v-secondary-clusters="node.secondaryClusters" size="tiny"></node-clusters-labels>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ Tea.context(function () {
|
|||||||
this.teaweb = teaweb
|
this.teaweb = teaweb
|
||||||
|
|
||||||
this.deleteNode = function (nodeId) {
|
this.deleteNode = function (nodeId) {
|
||||||
teaweb.confirm("确定要删除这个节点吗?", function () {
|
teaweb.confirm("确定要从当前集群中删除这个节点吗?", function () {
|
||||||
this.$post("/nodes/delete")
|
this.$post("/nodes/delete")
|
||||||
.params({
|
.params({
|
||||||
|
clusterId: this.clusterId,
|
||||||
nodeId: nodeId
|
nodeId: nodeId
|
||||||
})
|
})
|
||||||
.refresh();
|
.refresh();
|
||||||
|
|||||||
@@ -9,14 +9,14 @@
|
|||||||
|
|
||||||
<table class="ui table selectable definition">
|
<table class="ui table selectable definition">
|
||||||
<tr v-if="hasDomains">
|
<tr v-if="hasDomains">
|
||||||
<td>选择主域名</td>
|
<td>选择主域名 *</td>
|
||||||
<td>
|
<td>
|
||||||
<dns-domain-selector :v-domain-id="domainId" :v-domain-name="domainName"></dns-domain-selector>
|
<dns-domain-selector :v-domain-id="domainId" :v-domain-name="domainName"></dns-domain-selector>
|
||||||
<p class="comment">用于生成集群节点和网站服务的DNS解析记录。</p>
|
<p class="comment">用于生成集群节点和网站服务的DNS解析记录。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">DNS子域名</td>
|
<td class="title">DNS子域名 *</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui input right labeled">
|
<div class="ui input right labeled">
|
||||||
<input type="text" name="dnsName" maxlength="64" style="width:10em" v-model="dnsName"/>
|
<input type="text" name="dnsName" maxlength="64" style="width:10em" v-model="dnsName"/>
|
||||||
|
|||||||
5
web/views/@default/clusters/cluster/updateNodeSSH.js
Normal file
5
web/views/@default/clusters/cluster/updateNodeSSH.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
if (this.params.port <= 0) {
|
||||||
|
this.params.port = 22
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -114,6 +114,7 @@ Tea.context(function () {
|
|||||||
case "EMPTY_GRANT":
|
case "EMPTY_GRANT":
|
||||||
teaweb.warn("需要填写SSH登录信息", function () {
|
teaweb.warn("需要填写SSH登录信息", function () {
|
||||||
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
teaweb.popup("/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
||||||
|
height: "30em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.reload()
|
teaweb.reload()
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user