Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fcbed5f63e | ||
|
|
8d203a1d7c | ||
|
|
d6efb2dd12 | ||
|
|
6ea3938f74 | ||
|
|
63e773ce96 | ||
|
|
60b8e1041c | ||
|
|
fb263c926b | ||
|
|
dbbae30f5a | ||
|
|
7b73c86fa4 | ||
|
|
c16c6ea6a6 | ||
|
|
4ecba0040a | ||
|
|
f65aabe897 | ||
|
|
de2337afe7 | ||
|
|
3360f2fc08 | ||
|
|
7d8f3a9d9b | ||
|
|
63884bc836 | ||
|
|
9c231a2b8c | ||
|
|
6a5c979d2a | ||
|
|
094734ae1f | ||
|
|
97b4d457fd | ||
|
|
9669c0ddda | ||
|
|
daf8257a1f | ||
|
|
40f32c7cf9 | ||
|
|
b8295e5cfc | ||
|
|
aba489217a | ||
|
|
7775689dfa | ||
|
|
90397b2b6f | ||
|
|
32683a2b59 | ||
|
|
9e36847397 | ||
|
|
4c82804622 | ||
|
|
cb911c474e | ||
|
|
ce2537d69d | ||
|
|
38746e83c5 | ||
|
|
be8988d309 | ||
|
|
ed59994db8 | ||
|
|
11a8d3ba70 | ||
|
|
adf91bf3d0 | ||
|
|
7729b88a00 | ||
|
|
e93aecabb4 | ||
|
|
3cf43b2cc1 | ||
|
|
3cba8cf98d | ||
|
|
e2ca94c93b | ||
|
|
1c3e25ba1a | ||
|
|
f297f4ec52 | ||
|
|
534f10b8a7 | ||
|
|
a7aed3d49e | ||
|
|
9a915a48b5 | ||
|
|
81a3b299f0 | ||
|
|
a4edae6692 | ||
|
|
047f6c409f | ||
|
|
963be2bc63 | ||
|
|
bd34a9bd37 | ||
|
|
32b93b2bd9 | ||
|
|
e7c4507b0b | ||
|
|
17ae34c44f | ||
|
|
b466ea2fd1 | ||
|
|
8e4ee54f03 | ||
|
|
c99547d9e3 | ||
|
|
1d22125d6e | ||
|
|
d4689571cb | ||
|
|
cb1cb62e30 | ||
|
|
77ad860d35 | ||
|
|
5082561dc9 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*_plus.go
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# GoEdge目标
|
# GoEdge目标
|
||||||
做一款人人用得起的CDN & WAF系统。
|
做一款人人用得起的CDN & WAF系统。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
* `免费` - 开源、免费、自由、开放
|
* `免费` - 开源、免费、自由、开放
|
||||||
@@ -10,7 +10,8 @@
|
|||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
* [新手指南](https://edge.teaos.cn/docs/QuickStart/Index.md)
|
* [新手指南](https://edge.teaos.cn/docs/QuickStart/Index.md)
|
||||||
* [文档](http://edge.teaos.cn/docs)
|
* [完整文档](https://edge.teaos.cn/docs)
|
||||||
|
* [开发者指南](https://edge.teaos.cn/docs/Developer/Build.md)
|
||||||
|
|
||||||
## 架构
|
## 架构
|
||||||

|

|
||||||
|
|||||||
3
build/configs/.gitignore
vendored
3
build/configs/.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
api.yaml
|
api.yaml
|
||||||
server.yaml
|
server.yaml
|
||||||
api_db.yaml
|
api_db.yaml
|
||||||
*.pem
|
*.pem
|
||||||
|
*.cache.json
|
||||||
@@ -8,20 +8,22 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
|
"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web"
|
||||||
_ "github.com/iwind/TeaGo/bootstrap"
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
"github.com/iwind/gosock/pkg/gosock"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
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]").
|
Usage(teaconst.ProcessName+" [-v|start|stop|restart|service|daemon|reset|recover]").
|
||||||
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").
|
||||||
Option("stop", "stop the service").
|
Option("stop", "stop the service").
|
||||||
Option("service", "register service into systemd").
|
Option("service", "register service into systemd").
|
||||||
Option("daemon", "start the service with daemon").
|
Option("daemon", "start the service with daemon").
|
||||||
Option("reset", "reset configs")
|
Option("reset", "reset configs").
|
||||||
|
Option("recover", "enter recovery mode")
|
||||||
|
|
||||||
app.On("daemon", func() {
|
app.On("daemon", func() {
|
||||||
nodes.NewAdminNode().Daemon()
|
nodes.NewAdminNode().Daemon()
|
||||||
@@ -42,6 +44,19 @@ func main() {
|
|||||||
}
|
}
|
||||||
fmt.Println("done")
|
fmt.Println("done")
|
||||||
})
|
})
|
||||||
|
app.On("recover", 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: "recover"})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[ERROR]enter recovery mode failed: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("enter recovery mode successfully")
|
||||||
|
})
|
||||||
app.Run(func() {
|
app.Run(func() {
|
||||||
adminNode := nodes.NewAdminNode()
|
adminNode := nodes.NewAdminNode()
|
||||||
adminNode.Run()
|
adminNode.Run()
|
||||||
|
|||||||
11
go.mod
11
go.mod
@@ -9,12 +9,17 @@ require (
|
|||||||
github.com/cespare/xxhash v1.1.0
|
github.com/cespare/xxhash v1.1.0
|
||||||
github.com/go-sql-driver/mysql v1.5.0
|
github.com/go-sql-driver/mysql v1.5.0
|
||||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||||
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f
|
github.com/golang/protobuf v1.5.2
|
||||||
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
|
github.com/iwind/TeaGo v0.0.0-20210720011303-fc255c995afa
|
||||||
|
github.com/iwind/gosock v0.0.0-20210720054405-4030f271aa3f
|
||||||
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
|
||||||
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
|
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
|
||||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
|
||||||
google.golang.org/grpc v1.32.0
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
|
||||||
|
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect
|
||||||
|
google.golang.org/grpc v1.38.0
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||||
)
|
)
|
||||||
|
|||||||
72
go.sum
72
go.sum
@@ -13,6 +13,7 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+
|
|||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -20,6 +21,7 @@ github.com/dgryski/go-rendezvous v0.0.0-20200624174652-8d2f3be8b2d9/go.mod h1:cu
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/frankban/quicktest v1.5.0 h1:Tb4jWdSpdjKzTUicPnY61PZxKbDoGa7ABbrReT3gQVY=
|
github.com/frankban/quicktest v1.5.0 h1:Tb4jWdSpdjKzTUicPnY61PZxKbDoGa7ABbrReT3gQVY=
|
||||||
github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
||||||
@@ -42,22 +44,33 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
|
|||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||||
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f h1:r2O8PONj/KiuZjJHVHn7KlCePUIjNtgAmvLfgRafQ8o=
|
github.com/iwind/TeaGo v0.0.0-20210628135026-38575a4ab060/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||||
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
github.com/iwind/TeaGo v0.0.0-20210720011303-fc255c995afa h1:woN88uEmRRUNFD7pRZEtX9heDcjFn0ClMxjF5ButKow=
|
||||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
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-20210706152215-08fe64b7a8a3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
|
||||||
|
github.com/iwind/gosock v0.0.0-20210720054405-4030f271aa3f h1:+mKLTd5tCCLXK+iY5Xjz58hau6qFv9chGqcZ4FWUiIs=
|
||||||
|
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=
|
||||||
@@ -65,10 +78,12 @@ 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/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
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=
|
||||||
@@ -97,12 +112,14 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1
|
|||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/tealeg/xlsx/v3 v3.2.3 h1:MXnVh+9Y8cUglowItTy2HL3Kv6z+q/0aNjeKuTsVqZQ=
|
github.com/tealeg/xlsx/v3 v3.2.3 h1:MXnVh+9Y8cUglowItTy2HL3Kv6z+q/0aNjeKuTsVqZQ=
|
||||||
github.com/tealeg/xlsx/v3 v3.2.3/go.mod h1:0hGmAEoZ48SS1ZAE6eqZJkJVXgOMY+8a33vjXa8S8HA=
|
github.com/tealeg/xlsx/v3 v3.2.3/go.mod h1:0hGmAEoZ48SS1ZAE6eqZJkJVXgOMY+8a33vjXa8S8HA=
|
||||||
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119 h1:YyPWX3jLOtYKulBR6AScGIs74lLrJcgeKRwcbAuQOG4=
|
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119 h1:YyPWX3jLOtYKulBR6AScGIs74lLrJcgeKRwcbAuQOG4=
|
||||||
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119/go.mod h1:/nuTSlK+okRfR/vnIPqR89fFKonnWPiZymN5ydRJkX8=
|
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119/go.mod h1:/nuTSlK+okRfR/vnIPqR89fFKonnWPiZymN5ydRJkX8=
|
||||||
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
|
go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||||
@@ -115,9 +132,11 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o
|
|||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -126,13 +145,16 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
|
|
||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
|
||||||
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -146,35 +168,50 @@ golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
|
||||||
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus=
|
||||||
|
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
|
|
||||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
|
||||||
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@@ -183,8 +220,10 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
|||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
@@ -192,6 +231,7 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|||||||
@@ -2,17 +2,19 @@ package apps
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"github.com/iwind/gosock/pkg/gosock"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// App命令帮助
|
// AppCmd App命令帮助
|
||||||
type AppCmd struct {
|
type AppCmd struct {
|
||||||
product string
|
product string
|
||||||
version string
|
version string
|
||||||
@@ -21,10 +23,14 @@ type AppCmd struct {
|
|||||||
appendStrings []string
|
appendStrings []string
|
||||||
|
|
||||||
directives []*Directive
|
directives []*Directive
|
||||||
|
|
||||||
|
sock *gosock.Sock
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAppCmd() *AppCmd {
|
func NewAppCmd() *AppCmd {
|
||||||
return &AppCmd{}
|
return &AppCmd{
|
||||||
|
sock: gosock.NewTmpSock(teaconst.ProcessName),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandHelpOption struct {
|
type CommandHelpOption struct {
|
||||||
@@ -32,25 +38,25 @@ type CommandHelpOption struct {
|
|||||||
Description string
|
Description string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 产品
|
// Product 产品
|
||||||
func (this *AppCmd) Product(product string) *AppCmd {
|
func (this *AppCmd) Product(product string) *AppCmd {
|
||||||
this.product = product
|
this.product = product
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
// 版本
|
// Version 版本
|
||||||
func (this *AppCmd) Version(version string) *AppCmd {
|
func (this *AppCmd) Version(version string) *AppCmd {
|
||||||
this.version = version
|
this.version = version
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用方法
|
// Usage 使用方法
|
||||||
func (this *AppCmd) Usage(usage string) *AppCmd {
|
func (this *AppCmd) Usage(usage string) *AppCmd {
|
||||||
this.usage = usage
|
this.usage = usage
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选项
|
// Option 选项
|
||||||
func (this *AppCmd) Option(code string, description string) *AppCmd {
|
func (this *AppCmd) Option(code string, description string) *AppCmd {
|
||||||
this.options = append(this.options, &CommandHelpOption{
|
this.options = append(this.options, &CommandHelpOption{
|
||||||
Code: code,
|
Code: code,
|
||||||
@@ -59,13 +65,13 @@ func (this *AppCmd) Option(code string, description string) *AppCmd {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
// 附加内容
|
// Append 附加内容
|
||||||
func (this *AppCmd) Append(appendString string) *AppCmd {
|
func (this *AppCmd) Append(appendString string) *AppCmd {
|
||||||
this.appendStrings = append(this.appendStrings, appendString)
|
this.appendStrings = append(this.appendStrings, appendString)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打印
|
// Print 打印
|
||||||
func (this *AppCmd) Print() {
|
func (this *AppCmd) Print() {
|
||||||
fmt.Println(this.product + " v" + this.version)
|
fmt.Println(this.product + " v" + this.version)
|
||||||
|
|
||||||
@@ -104,7 +110,7 @@ func (this *AppCmd) Print() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加指令
|
// On 添加指令
|
||||||
func (this *AppCmd) On(arg string, callback func()) {
|
func (this *AppCmd) On(arg string, callback func()) {
|
||||||
this.directives = append(this.directives, &Directive{
|
this.directives = append(this.directives, &Directive{
|
||||||
Arg: arg,
|
Arg: arg,
|
||||||
@@ -112,7 +118,7 @@ func (this *AppCmd) On(arg string, callback func()) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 运行
|
// Run 运行
|
||||||
func (this *AppCmd) Run(main func()) {
|
func (this *AppCmd) Run(main func()) {
|
||||||
// 获取参数
|
// 获取参数
|
||||||
args := os.Args[1:]
|
args := os.Args[1:]
|
||||||
@@ -151,9 +157,6 @@ func (this *AppCmd) Run(main func()) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 记录PID
|
|
||||||
_ = this.writePid()
|
|
||||||
|
|
||||||
// 日志
|
// 日志
|
||||||
writer := new(LogWriter)
|
writer := new(LogWriter)
|
||||||
writer.Init()
|
writer.Init()
|
||||||
@@ -175,9 +178,9 @@ func (this *AppCmd) runHelp() {
|
|||||||
|
|
||||||
// 启动
|
// 启动
|
||||||
func (this *AppCmd) runStart() {
|
func (this *AppCmd) runStart() {
|
||||||
proc := this.checkPid()
|
var pid = this.getPID()
|
||||||
if proc != nil {
|
if pid > 0 {
|
||||||
fmt.Println(this.product+" already started, pid:", proc.Pid)
|
fmt.Println(this.product+" already started, pid:", pid)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,18 +196,15 @@ func (this *AppCmd) runStart() {
|
|||||||
|
|
||||||
// 停止
|
// 停止
|
||||||
func (this *AppCmd) runStop() {
|
func (this *AppCmd) runStop() {
|
||||||
proc := this.checkPid()
|
var pid = this.getPID()
|
||||||
if proc == nil {
|
if pid == 0 {
|
||||||
fmt.Println(this.product + " not started yet")
|
fmt.Println(this.product + " not started yet")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 停止进程
|
_, _ = this.sock.Send(&gosock.Command{Code: "stop"})
|
||||||
_ = proc.Signal(syscall.SIGQUIT)
|
|
||||||
|
|
||||||
// 在Windows上经常不能及时释放资源
|
fmt.Println(this.product+" stopped ok, pid:", types.String(pid))
|
||||||
_ = DeletePid(Tea.Root + "/bin/pid")
|
|
||||||
fmt.Println(this.product+" stopped ok, pid:", proc.Pid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重启
|
// 重启
|
||||||
@@ -216,20 +216,24 @@ func (this *AppCmd) runRestart() {
|
|||||||
|
|
||||||
// 状态
|
// 状态
|
||||||
func (this *AppCmd) runStatus() {
|
func (this *AppCmd) runStatus() {
|
||||||
proc := this.checkPid()
|
var pid = this.getPID()
|
||||||
if proc == nil {
|
if pid == 0 {
|
||||||
fmt.Println(this.product + " not started yet")
|
fmt.Println(this.product + " not started yet")
|
||||||
} else {
|
return
|
||||||
fmt.Println(this.product + " is running, pid: " + fmt.Sprintf("%d", proc.Pid))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println(this.product + " is running, pid: " + types.String(pid))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查PID
|
// 获取当前的PID
|
||||||
func (this *AppCmd) checkPid() *os.Process {
|
func (this *AppCmd) getPID() int {
|
||||||
return CheckPid(Tea.Root + "/bin/pid")
|
if !this.sock.IsListening() {
|
||||||
}
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// 写入PID
|
reply, err := this.sock.Send(&gosock.Command{Code: "pid"})
|
||||||
func (this *AppCmd) writePid() error {
|
if err != nil {
|
||||||
return WritePid(Tea.Root + "/bin/pid")
|
return 0
|
||||||
|
}
|
||||||
|
return maps.NewMap(reply.Params).GetInt("pid")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package apps
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// lock file
|
|
||||||
func LockFile(fp *os.File) error {
|
|
||||||
return syscall.Flock(int(fp.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnlockFile(fp *os.File) error {
|
|
||||||
return syscall.Flock(int(fp.Fd()), syscall.LOCK_UN)
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// +build windows
|
|
||||||
|
|
||||||
package apps
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// lock file
|
|
||||||
func LockFile(fp *os.File) error {
|
|
||||||
return errors.New("not implemented on windows")
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnlockFile(fp *os.File) error {
|
|
||||||
return errors.New("not implemented on windows")
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
package apps
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/iwind/TeaGo/types"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
var pidFileList = []*os.File{}
|
|
||||||
|
|
||||||
// 检查Pid
|
|
||||||
func CheckPid(path string) *os.Process {
|
|
||||||
// windows上打开的文件是不能删除的
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
if os.Remove(path) == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
_ = file.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 是否能取得Lock
|
|
||||||
err = LockFile(file)
|
|
||||||
if err == nil {
|
|
||||||
_ = UnlockFile(file)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pidBytes, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
pid := types.Int(string(pidBytes))
|
|
||||||
|
|
||||||
if pid <= 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
proc, _ := os.FindProcess(pid)
|
|
||||||
return proc
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写入Pid
|
|
||||||
func WritePid(path string) error {
|
|
||||||
fp, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_RDONLY, 0666)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if runtime.GOOS != "windows" {
|
|
||||||
err = LockFile(fp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pidFileList = append(pidFileList, fp) // hold the file pointers
|
|
||||||
|
|
||||||
_, err = fp.WriteString(fmt.Sprintf("%d", os.Getpid()))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写入Ppid
|
|
||||||
func WritePpid(path string) error {
|
|
||||||
fp, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_RDONLY, 0666)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if runtime.GOOS != "windows" {
|
|
||||||
err = LockFile(fp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pidFileList = append(pidFileList, fp) // hold the file pointers
|
|
||||||
|
|
||||||
_, err = fp.WriteString(fmt.Sprintf("%d", os.Getppid()))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除Pid
|
|
||||||
func DeletePid(path string) error {
|
|
||||||
_, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
if !os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fp := range pidFileList {
|
|
||||||
_ = UnlockFile(fp)
|
|
||||||
_ = fp.Close()
|
|
||||||
}
|
|
||||||
return os.Remove(path)
|
|
||||||
}
|
|
||||||
@@ -44,6 +44,7 @@ func loadAdminModuleMapping() (map[int64]*AdminModuleList, error) {
|
|||||||
list := &AdminModuleList{
|
list := &AdminModuleList{
|
||||||
IsSuper: m.IsSuper,
|
IsSuper: m.IsSuper,
|
||||||
Fullname: m.Fullname,
|
Fullname: m.Fullname,
|
||||||
|
Theme: m.Theme,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pbModule := range m.Modules {
|
for _, pbModule := range m.Modules {
|
||||||
@@ -132,6 +133,29 @@ func FindAdminFullname(adminId int64) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindAdminTheme 查找某个管理员选择的风格
|
||||||
|
func FindAdminTheme(adminId int64) string {
|
||||||
|
locker.Lock()
|
||||||
|
defer locker.Unlock()
|
||||||
|
|
||||||
|
list, ok := sharedAdminModuleMapping[adminId]
|
||||||
|
if ok {
|
||||||
|
return list.Theme
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateAdminTheme 设置某个管理员的风格
|
||||||
|
func UpdateAdminTheme(adminId int64, theme string) {
|
||||||
|
locker.Lock()
|
||||||
|
defer locker.Unlock()
|
||||||
|
|
||||||
|
list, ok := sharedAdminModuleMapping[adminId]
|
||||||
|
if ok {
|
||||||
|
list.Theme = theme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AllModuleMaps 所有权限列表
|
// AllModuleMaps 所有权限列表
|
||||||
func AllModuleMaps() []maps.Map {
|
func AllModuleMaps() []maps.Map {
|
||||||
m := []maps.Map{
|
m := []maps.Map{
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ type AdminModuleList struct {
|
|||||||
IsSuper bool
|
IsSuper bool
|
||||||
Modules []*systemconfigs.AdminModule
|
Modules []*systemconfigs.AdminModule
|
||||||
Fullname string
|
Fullname string
|
||||||
|
Theme string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *AdminModuleList) Allow(module string) bool {
|
func (this *AdminModuleList) Allow(module string) bool {
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ func (this *APIConfig) WriteFile(path string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(path, data, 0666)
|
|
||||||
|
|
||||||
// 写入 ~/ 和 /etc/ 目录,因为是备份需要,所以不需要提示错误信息
|
// 写入 ~/ 和 /etc/ 目录,因为是备份需要,所以不需要提示错误信息
|
||||||
// 写入 ~/.edge-admin/
|
// 写入 ~/.edge-admin/
|
||||||
@@ -141,5 +140,10 @@ func (this *APIConfig) WriteFile(path string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
err = ioutil.WriteFile(path, data, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
40
internal/configs/plus_config.go
Normal file
40
internal/configs/plus_config.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package configs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var plusConfigFile = "plus.cache.json"
|
||||||
|
|
||||||
|
type PlusConfig struct {
|
||||||
|
IsPlus bool `json:"isPlus"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadPlusConfig() *PlusConfig {
|
||||||
|
data, err := ioutil.ReadFile(Tea.ConfigFile(plusConfigFile))
|
||||||
|
if err != nil {
|
||||||
|
return &PlusConfig{IsPlus: false}
|
||||||
|
}
|
||||||
|
var config = &PlusConfig{IsPlus: false}
|
||||||
|
err = json.Unmarshal(data, config)
|
||||||
|
if err != nil {
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
func WritePlusConfig(config *PlusConfig) error {
|
||||||
|
configJSON, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(Tea.ConfigFile(plusConfigFile), configJSON, 0777)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "0.2.2"
|
Version = "0.2.5"
|
||||||
|
|
||||||
ProductName = "Edge Admin"
|
ProductName = "Edge Admin"
|
||||||
ProcessName = "edge-admin"
|
ProcessName = "edge-admin"
|
||||||
|
|||||||
7
internal/const/vars.go
Normal file
7
internal/const/vars.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package teaconst
|
||||||
|
|
||||||
|
var (
|
||||||
|
IsRecoverMode = false
|
||||||
|
)
|
||||||
@@ -10,11 +10,12 @@ import (
|
|||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/lists"
|
"github.com/iwind/TeaGo/lists"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/rands"
|
"github.com/iwind/TeaGo/rands"
|
||||||
"github.com/iwind/TeaGo/sessions"
|
"github.com/iwind/TeaGo/sessions"
|
||||||
|
"github.com/iwind/gosock/pkg/gosock"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@@ -25,6 +26,7 @@ import (
|
|||||||
var SharedAdminNode *AdminNode = nil
|
var SharedAdminNode *AdminNode = nil
|
||||||
|
|
||||||
type AdminNode struct {
|
type AdminNode struct {
|
||||||
|
sock *gosock.Sock
|
||||||
subPIDs []int
|
subPIDs []int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +44,7 @@ func (this *AdminNode) Run() {
|
|||||||
// 本地Sock
|
// 本地Sock
|
||||||
err := this.listenSock()
|
err := this.listenSock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Println("NODE" + err.Error())
|
logs.Println("[NODE]", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,11 +91,11 @@ func (this *AdminNode) Run() {
|
|||||||
|
|
||||||
// Daemon 实现守护进程
|
// Daemon 实现守护进程
|
||||||
func (this *AdminNode) Daemon() {
|
func (this *AdminNode) Daemon() {
|
||||||
path := os.TempDir() + "/edge-admin.sock"
|
var sock = gosock.NewTmpSock(teaconst.ProcessName)
|
||||||
isDebug := lists.ContainsString(os.Args, "debug")
|
isDebug := lists.ContainsString(os.Args, "debug")
|
||||||
isDebug = true
|
isDebug = true
|
||||||
for {
|
for {
|
||||||
conn, err := net.DialTimeout("unix", path, 1*time.Second)
|
conn, err := sock.Dial()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isDebug {
|
if isDebug {
|
||||||
log.Println("[DAEMON]starting ...")
|
log.Println("[DAEMON]starting ...")
|
||||||
@@ -281,37 +283,59 @@ func (this *AdminNode) genSecret() string {
|
|||||||
|
|
||||||
// 监听本地sock
|
// 监听本地sock
|
||||||
func (this *AdminNode) listenSock() error {
|
func (this *AdminNode) listenSock() error {
|
||||||
path := os.TempDir() + "/edge-admin.sock"
|
this.sock = gosock.NewTmpSock(teaconst.ProcessName)
|
||||||
|
|
||||||
// 检查是否已经存在
|
// 检查是否在运行
|
||||||
_, err := os.Stat(path)
|
if this.sock.IsListening() {
|
||||||
if err == nil {
|
reply, err := this.sock.Send(&gosock.Command{Code: "pid"})
|
||||||
conn, err := net.Dial("unix", path)
|
if err == nil {
|
||||||
if err != nil {
|
return errors.New("error: the process is already running, pid: " + maps.NewMap(reply.Params).GetString("pid"))
|
||||||
_ = os.Remove(path)
|
|
||||||
} else {
|
} else {
|
||||||
_ = conn.Close()
|
return errors.New("error: the process is already running")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新的监听任务
|
// 启动监听
|
||||||
listener, err := net.Listen("unix", path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
events.On(events.EventQuit, func() {
|
|
||||||
logs.Println("NODE", "quit unix sock")
|
|
||||||
_ = listener.Close()
|
|
||||||
})
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
this.sock.OnCommand(func(cmd *gosock.Command) {
|
||||||
_, err := listener.Accept()
|
switch cmd.Code {
|
||||||
if err != nil {
|
case "pid":
|
||||||
return
|
_ = cmd.Reply(&gosock.Command{
|
||||||
|
Code: "pid",
|
||||||
|
Params: map[string]interface{}{
|
||||||
|
"pid": os.Getpid(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
case "stop":
|
||||||
|
_ = cmd.ReplyOk()
|
||||||
|
|
||||||
|
// 关闭子进程
|
||||||
|
for _, pid := range this.subPIDs {
|
||||||
|
p, err := os.FindProcess(pid)
|
||||||
|
if err == nil && p != nil {
|
||||||
|
_ = p.Kill()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退出主进程
|
||||||
|
events.Notify(events.EventQuit)
|
||||||
|
os.Exit(0)
|
||||||
|
case "recover":
|
||||||
|
teaconst.IsRecoverMode = true
|
||||||
|
_ = cmd.ReplyOk()
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
err := this.sock.Listen()
|
||||||
|
if err != nil {
|
||||||
|
logs.Println("NODE", err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
events.On(events.EventQuit, func() {
|
||||||
|
logs.Println("NODE", "quit unix sock")
|
||||||
|
_ = this.sock.Close()
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package rpc
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type ContextInterface interface {
|
|
||||||
AdminContext() context.Context
|
|
||||||
}
|
|
||||||
@@ -51,6 +51,10 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
|
|||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) APITokenRPC() pb.APITokenServiceClient {
|
||||||
|
return pb.NewAPITokenServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) AdminRPC() pb.AdminServiceClient {
|
func (this *RPCClient) AdminRPC() pb.AdminServiceClient {
|
||||||
return pb.NewAdminServiceClient(this.pickConn())
|
return pb.NewAdminServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -207,6 +211,10 @@ func (this *RPCClient) HTTPFirewallRuleSetRPC() pb.HTTPFirewallRuleSetServiceCli
|
|||||||
return pb.NewHTTPFirewallRuleSetServiceClient(this.pickConn())
|
return pb.NewHTTPFirewallRuleSetServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) FirewallRPC() pb.FirewallServiceClient {
|
||||||
|
return pb.NewFirewallServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) HTTPLocationRPC() pb.HTTPLocationServiceClient {
|
func (this *RPCClient) HTTPLocationRPC() pb.HTTPLocationServiceClient {
|
||||||
return pb.NewHTTPLocationServiceClient(this.pickConn())
|
return pb.NewHTTPLocationServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -228,6 +236,10 @@ func (this *RPCClient) HTTPFastcgiRPC() pb.HTTPFastcgiServiceClient {
|
|||||||
return pb.NewHTTPFastcgiServiceClient(this.pickConn())
|
return pb.NewHTTPFastcgiServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) HTTPAuthPolicyRPC() pb.HTTPAuthPolicyServiceClient {
|
||||||
|
return pb.NewHTTPAuthPolicyServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) SSLCertRPC() pb.SSLCertServiceClient {
|
func (this *RPCClient) SSLCertRPC() pb.SSLCertServiceClient {
|
||||||
return pb.NewSSLCertServiceClient(this.pickConn())
|
return pb.NewSSLCertServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -384,6 +396,34 @@ func (this *RPCClient) NSAccessLogRPC() pb.NSAccessLogServiceClient {
|
|||||||
return pb.NewNSAccessLogServiceClient(this.pickConn())
|
return pb.NewNSAccessLogServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) NSRPC() pb.NSServiceClient {
|
||||||
|
return pb.NewNSServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient {
|
||||||
|
return pb.NewMetricItemServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) MetricStatRPC() pb.MetricStatServiceClient {
|
||||||
|
return pb.NewMetricStatServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) MetricChartRPC() pb.MetricChartServiceClient {
|
||||||
|
return pb.NewMetricChartServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) NodeClusterMetricItemRPC() pb.NodeClusterMetricItemServiceClient {
|
||||||
|
return pb.NewNodeClusterMetricItemServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) ServerStatBoardRPC() pb.ServerStatBoardServiceClient {
|
||||||
|
return pb.NewServerStatBoardServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) ServerStatBoardChartRPC() pb.ServerStatBoardChartServiceClient {
|
||||||
|
return pb.NewServerStatBoardChartServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
// Context 构造Admin上下文
|
// Context 构造Admin上下文
|
||||||
func (this *RPCClient) Context(adminId int64) context.Context {
|
func (this *RPCClient) Context(adminId int64) context.Context {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package tasks
|
package tasks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
@@ -10,6 +11,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,6 +30,13 @@ func NewAuthorityTask() *AuthorityTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *AuthorityTask) Start() {
|
func (this *AuthorityTask) Start() {
|
||||||
|
// 从缓存中读取
|
||||||
|
config := configs.ReadPlusConfig()
|
||||||
|
if config != nil {
|
||||||
|
teaconst.IsPlus = config.IsPlus
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始计时器
|
||||||
ticker := time.NewTicker(10 * time.Minute)
|
ticker := time.NewTicker(10 * time.Minute)
|
||||||
if Tea.IsTesting() {
|
if Tea.IsTesting() {
|
||||||
// 快速测试
|
// 快速测试
|
||||||
@@ -65,10 +74,16 @@ func (this *AuthorityTask) Loop() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if resp.AuthorityKey != nil {
|
var oldState = teaconst.IsPlus
|
||||||
|
if resp.AuthorityKey != nil && len(resp.AuthorityKey.Value) > 0 && resp.AuthorityKey.DayTo >= timeutil.Format("Y-m-d") {
|
||||||
teaconst.IsPlus = true
|
teaconst.IsPlus = true
|
||||||
} else {
|
} else {
|
||||||
teaconst.IsPlus = false
|
teaconst.IsPlus = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if oldState != teaconst.IsPlus {
|
||||||
|
_ = configs.WritePlusConfig(&configs.PlusConfig{IsPlus: teaconst.IsPlus})
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
package tasks
|
package tasks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials"
|
||||||
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,7 +27,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// API节点同步任务
|
// SyncAPINodesTask API节点同步任务
|
||||||
type SyncAPINodesTask struct {
|
type SyncAPINodesTask struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +51,7 @@ func (this *SyncAPINodesTask) Start() {
|
|||||||
|
|
||||||
func (this *SyncAPINodesTask) Loop() error {
|
func (this *SyncAPINodesTask) Loop() error {
|
||||||
// 如果还没有安装直接返回
|
// 如果还没有安装直接返回
|
||||||
if !setup.IsConfigured() {
|
if !setup.IsConfigured() || teaconst.IsRecoverMode {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +82,12 @@ func (this *SyncAPINodesTask) Loop() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 测试是否有API节点可用
|
||||||
|
hasOk := this.testEndpoints(newEndpoints)
|
||||||
|
if !hasOk {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// 修改RPC对象配置
|
// 修改RPC对象配置
|
||||||
config.RPC.Endpoints = newEndpoints
|
config.RPC.Endpoints = newEndpoints
|
||||||
err = rpcClient.UpdateConfig(config)
|
err = rpcClient.UpdateConfig(config)
|
||||||
@@ -96,3 +109,47 @@ func (this *SyncAPINodesTask) isSame(endpoints1 []string, endpoints2 []string) b
|
|||||||
sort.Strings(endpoints2)
|
sort.Strings(endpoints2)
|
||||||
return strings.Join(endpoints1, "&") == strings.Join(endpoints2, "&")
|
return strings.Join(endpoints1, "&") == strings.Join(endpoints2, "&")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *SyncAPINodesTask) testEndpoints(endpoints []string) bool {
|
||||||
|
if len(endpoints) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg = sync.WaitGroup{}
|
||||||
|
wg.Add(len(endpoints))
|
||||||
|
|
||||||
|
var ok = false
|
||||||
|
|
||||||
|
for _, endpoint := range endpoints {
|
||||||
|
go func(endpoint string) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
u, err := url.Parse(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer func() {
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
var conn *grpc.ClientConn
|
||||||
|
if u.Scheme == "http" {
|
||||||
|
conn, err = grpc.DialContext(ctx, u.Host, grpc.WithInsecure(), grpc.WithBlock())
|
||||||
|
} else if u.Scheme == "https" {
|
||||||
|
conn, err = grpc.DialContext(ctx, u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
})), grpc.WithBlock())
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = conn.Close()
|
||||||
|
|
||||||
|
ok = true
|
||||||
|
}(endpoint)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package tasks
|
package tasks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
||||||
@@ -40,7 +41,7 @@ func (this *SyncClusterTask) Start() {
|
|||||||
|
|
||||||
func (this *SyncClusterTask) loop() error {
|
func (this *SyncClusterTask) loop() error {
|
||||||
// 如果还没有安装直接返回
|
// 如果还没有安装直接返回
|
||||||
if !setup.IsConfigured() {
|
if !setup.IsConfigured() || teaconst.IsRecoverMode {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 获取CNAME
|
// LookupCNAME 获取CNAME
|
||||||
func LookupCNAME(host string) (string, error) {
|
func LookupCNAME(host string) (string, error) {
|
||||||
config, err := dns.ClientConfigFromFile("/etc/resolv.conf")
|
config, err := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
15
internal/web/actions/actionutils/action_interface.go
Normal file
15
internal/web/actions/actionutils/action_interface.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package actionutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ActionInterface interface {
|
||||||
|
RPC() *rpc.RPCClient
|
||||||
|
|
||||||
|
AdminContext() context.Context
|
||||||
|
|
||||||
|
ViewData() maps.Map
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
@@ -126,3 +127,8 @@ func (this *ParentAction) AdminContext() context.Context {
|
|||||||
}
|
}
|
||||||
return this.rpcClient.Context(this.AdminId())
|
return this.rpcClient.Context(this.AdminId())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ViewData 视图里可以使用的数据
|
||||||
|
func (this *ParentAction) ViewData() maps.Map {
|
||||||
|
return this.Data
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package accesskeys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreatePopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunGet(params struct {
|
||||||
|
AdminId int64
|
||||||
|
}) {
|
||||||
|
this.Data["adminId"] = params.AdminId
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunPost(params struct {
|
||||||
|
AdminId int64
|
||||||
|
Description string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
params.Must.
|
||||||
|
Field("description", params.Description).
|
||||||
|
Require("请输入备注")
|
||||||
|
|
||||||
|
accessKeyIdResp, err := this.RPC().UserAccessKeyRPC().CreateUserAccessKey(this.AdminContext(), &pb.CreateUserAccessKeyRequest{
|
||||||
|
AdminId: params.AdminId,
|
||||||
|
Description: params.Description,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer this.CreateLogInfo("创建AccessKey %d", accessKeyIdResp.UserAccessKeyId)
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
24
internal/web/actions/default/admins/accesskeys/delete.go
Normal file
24
internal/web/actions/default/admins/accesskeys/delete.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package accesskeys
|
||||||
|
|
||||||
|
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 {
|
||||||
|
AccessKeyId int64
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("删除AccessKey %d", params.AccessKeyId)
|
||||||
|
|
||||||
|
_, err := this.RPC().UserAccessKeyRPC().DeleteUserAccessKey(this.AdminContext(), &pb.DeleteUserAccessKeyRequest{UserAccessKeyId: params.AccessKeyId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
54
internal/web/actions/default/admins/accesskeys/index.go
Normal file
54
internal/web/actions/default/admins/accesskeys/index.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package accesskeys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/admins/adminutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "accessKey")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
AdminId int64
|
||||||
|
}) {
|
||||||
|
err := adminutils.InitAdmin(this.Parent(), params.AdminId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
accessKeysResp, err := this.RPC().UserAccessKeyRPC().FindAllEnabledUserAccessKeys(this.AdminContext(), &pb.FindAllEnabledUserAccessKeysRequest{AdminId: params.AdminId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
accessKeyMaps := []maps.Map{}
|
||||||
|
for _, accessKey := range accessKeysResp.UserAccessKeys {
|
||||||
|
var accessedTime string
|
||||||
|
if accessKey.AccessedAt > 0 {
|
||||||
|
accessedTime = timeutil.FormatTime("Y-m-d H:i:s", accessKey.AccessedAt)
|
||||||
|
}
|
||||||
|
accessKeyMaps = append(accessKeyMaps, maps.Map{
|
||||||
|
"id": accessKey.Id,
|
||||||
|
"isOn": accessKey.IsOn,
|
||||||
|
"uniqueId": accessKey.UniqueId,
|
||||||
|
"secret": accessKey.Secret,
|
||||||
|
"description": accessKey.Description,
|
||||||
|
"accessedTime": accessedTime,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["accessKeys"] = accessKeyMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
28
internal/web/actions/default/admins/accesskeys/updateIsOn.go
Normal file
28
internal/web/actions/default/admins/accesskeys/updateIsOn.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package accesskeys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateIsOnAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateIsOnAction) RunPost(params struct {
|
||||||
|
AccessKeyId int64
|
||||||
|
IsOn bool
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("设置AccessKey %d 启用状态", params.AccessKeyId)
|
||||||
|
|
||||||
|
_, err := this.RPC().UserAccessKeyRPC().UpdateUserAccessKeyIsOn(this.AdminContext(), &pb.UpdateUserAccessKeyIsOnRequest{
|
||||||
|
UserAccessKeyId: params.AccessKeyId,
|
||||||
|
IsOn: params.IsOn,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -30,13 +30,22 @@ func (this *AdminAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AccessKey数量
|
||||||
|
countAccessKeyResp, err := this.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(this.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{AdminId: params.AdminId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
countAccessKeys := countAccessKeyResp.Count
|
||||||
|
|
||||||
this.Data["admin"] = maps.Map{
|
this.Data["admin"] = maps.Map{
|
||||||
"id": admin.Id,
|
"id": admin.Id,
|
||||||
"fullname": admin.Fullname,
|
"fullname": admin.Fullname,
|
||||||
"username": admin.Username,
|
"username": admin.Username,
|
||||||
"isOn": admin.IsOn,
|
"isOn": admin.IsOn,
|
||||||
"isSuper": admin.IsSuper,
|
"isSuper": admin.IsSuper,
|
||||||
"canLogin": admin.CanLogin,
|
"canLogin": admin.CanLogin,
|
||||||
|
"countAccessKeys": countAccessKeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 权限
|
// 权限
|
||||||
|
|||||||
38
internal/web/actions/default/admins/adminutils/utils.go
Normal file
38
internal/web/actions/default/admins/adminutils/utils.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package adminutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitAdmin 查找管理员基本信息
|
||||||
|
func InitAdmin(p *actionutils.ParentAction, adminId int64) error {
|
||||||
|
// 管理员信息
|
||||||
|
resp, err := p.RPC().AdminRPC().FindEnabledAdmin(p.AdminContext(), &pb.FindEnabledAdminRequest{AdminId: adminId})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.Admin == nil {
|
||||||
|
return errors.New("not found admin")
|
||||||
|
}
|
||||||
|
var admin = resp.Admin
|
||||||
|
|
||||||
|
// AccessKey数量
|
||||||
|
countAccessKeysResp, err := p.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(p.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{
|
||||||
|
AdminId: adminId,
|
||||||
|
UserId: 0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Data["admin"] = maps.Map{
|
||||||
|
"id": admin.Id,
|
||||||
|
"username": admin.Username,
|
||||||
|
"fullname": admin.Fullname,
|
||||||
|
"countAccessKeys": countAccessKeysResp.Count,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package admins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/admins/accesskeys"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/iwind/TeaGo"
|
"github.com/iwind/TeaGo"
|
||||||
)
|
)
|
||||||
@@ -19,6 +20,15 @@ func init() {
|
|||||||
Get("/admin", new(AdminAction)).
|
Get("/admin", new(AdminAction)).
|
||||||
Get("/otpQrcode", new(OtpQrcodeAction)).
|
Get("/otpQrcode", new(OtpQrcodeAction)).
|
||||||
Post("/options", new(OptionsAction)).
|
Post("/options", new(OptionsAction)).
|
||||||
|
|
||||||
|
// AccessKeys
|
||||||
|
Prefix("/admins/accessKeys").
|
||||||
|
Get("", new(accesskeys.IndexAction)).
|
||||||
|
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
||||||
|
Post("/delete", new(accesskeys.DeleteAction)).
|
||||||
|
Post("/updateIsOn", new(accesskeys.UpdateIsOnAction)).
|
||||||
|
|
||||||
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,14 +39,23 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
otpLoginIsOn = admin.OtpLogin.IsOn
|
otpLoginIsOn = admin.OtpLogin.IsOn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AccessKey数量
|
||||||
|
countAccessKeyResp, err := this.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(this.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{AdminId: params.AdminId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
countAccessKeys := countAccessKeyResp.Count
|
||||||
|
|
||||||
this.Data["admin"] = maps.Map{
|
this.Data["admin"] = maps.Map{
|
||||||
"id": admin.Id,
|
"id": admin.Id,
|
||||||
"fullname": admin.Fullname,
|
"fullname": admin.Fullname,
|
||||||
"username": admin.Username,
|
"username": admin.Username,
|
||||||
"isOn": admin.IsOn,
|
"isOn": admin.IsOn,
|
||||||
"isSuper": admin.IsSuper,
|
"isSuper": admin.IsSuper,
|
||||||
"canLogin": admin.CanLogin,
|
"canLogin": admin.CanLogin,
|
||||||
"otpLoginIsOn": otpLoginIsOn,
|
"otpLoginIsOn": otpLoginIsOn,
|
||||||
|
"countAccessKeys": countAccessKeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 权限
|
// 权限
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 监听地址
|
// 监听地址
|
||||||
|
var hasHTTPS = false
|
||||||
httpConfig := &serverconfigs.HTTPProtocolConfig{}
|
httpConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||||
if len(node.HttpJSON) > 0 {
|
if len(node.HttpJSON) > 0 {
|
||||||
err = json.Unmarshal(node.HttpJSON, httpConfig)
|
err = json.Unmarshal(node.HttpJSON, httpConfig)
|
||||||
@@ -47,6 +48,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
hasHTTPS = len(httpsConfig.Listen) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听地址
|
// 监听地址
|
||||||
@@ -56,7 +58,6 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
|
|
||||||
// 证书信息
|
// 证书信息
|
||||||
certs := []*sslconfigs.SSLCertConfig{}
|
certs := []*sslconfigs.SSLCertConfig{}
|
||||||
sslPolicyId := int64(0)
|
|
||||||
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 {
|
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 {
|
||||||
sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId})
|
sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -65,8 +66,6 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
sslPolicyConfigJSON := sslPolicyConfigResp.SslPolicyJSON
|
sslPolicyConfigJSON := sslPolicyConfigResp.SslPolicyJSON
|
||||||
if len(sslPolicyConfigJSON) > 0 {
|
if len(sslPolicyConfigJSON) > 0 {
|
||||||
sslPolicyId = httpsConfig.SSLPolicyRef.SSLPolicyId
|
|
||||||
|
|
||||||
sslPolicy := &sslconfigs.SSLPolicy{}
|
sslPolicy := &sslconfigs.SSLPolicy{}
|
||||||
err = json.Unmarshal(sslPolicyConfigJSON, sslPolicy)
|
err = json.Unmarshal(sslPolicyConfigJSON, sslPolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -112,6 +111,10 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
if httpsConfig.IsOn && len(httpsConfig.Listen) > 0 {
|
if httpsConfig.IsOn && len(httpsConfig.Listen) > 0 {
|
||||||
restAccessAddrs = append(restAccessAddrs, httpsConfig.Listen...)
|
restAccessAddrs = append(restAccessAddrs, httpsConfig.Listen...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !hasHTTPS {
|
||||||
|
hasHTTPS = len(httpsConfig.Listen) > 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +127,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
"accessAddrs": accessAddrs,
|
"accessAddrs": accessAddrs,
|
||||||
"restIsOn": node.RestIsOn,
|
"restIsOn": node.RestIsOn,
|
||||||
"restAccessAddrs": restAccessAddrs,
|
"restAccessAddrs": restAccessAddrs,
|
||||||
"hasHTTPS": sslPolicyId > 0,
|
"hasHTTPS": hasHTTPS,
|
||||||
"certs": certs,
|
"certs": certs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存基础设置
|
// RunPost 保存基础设置
|
||||||
func (this *UpdateAction) RunPost(params struct {
|
func (this *UpdateAction) RunPost(params struct {
|
||||||
NodeId int64
|
NodeId int64
|
||||||
Name string
|
Name string
|
||||||
|
|||||||
182
internal/web/actions/default/clusters/cluster/boards/index.go
Normal file
182
internal/web/actions/default/clusters/cluster/boards/index.go
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package boards
|
||||||
|
|
||||||
|
import (
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "board", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
}) {
|
||||||
|
if !teaconst.IsPlus {
|
||||||
|
this.RedirectURL("/clusters/cluster?clusterId=" + strconv.FormatInt(params.ClusterId, 10))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := this.RPC().ServerStatBoardRPC().ComposeServerStatNodeClusterBoard(this.AdminContext(), &pb.ComposeServerStatNodeClusterBoardRequest{NodeClusterId: params.ClusterId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["board"] = maps.Map{
|
||||||
|
"countUsers": resp.CountUsers,
|
||||||
|
"countActiveNodes": resp.CountActiveNodes,
|
||||||
|
"countInactiveNodes": resp.CountInactiveNodes,
|
||||||
|
"countServers": resp.CountServers,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 24小时流量趋势
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.HourlyTrafficStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
"cachedBytes": stat.CachedBytes,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"countCachedRequests": stat.CountCachedRequests,
|
||||||
|
"countAttackRequests": stat.CountAttackRequests,
|
||||||
|
"attackBytes": stat.AttackBytes,
|
||||||
|
"day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
|
||||||
|
"hour": stat.Hour[8:],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["hourlyStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 15天流量趋势
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.DailyTrafficStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
"cachedBytes": stat.CachedBytes,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"countCachedRequests": stat.CountCachedRequests,
|
||||||
|
"countAttackRequests": stat.CountAttackRequests,
|
||||||
|
"attackBytes": stat.AttackBytes,
|
||||||
|
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["dailyStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点排行
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.TopNodeStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"nodeId": stat.NodeId,
|
||||||
|
"nodeName": stat.NodeName,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["topNodeStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 域名排行
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.TopDomainStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"serverId": stat.ServerId,
|
||||||
|
"domain": stat.Domain,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["topDomainStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPU
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.CpuNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["cpuValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.MemoryNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["memoryValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.LoadNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["loadValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指标
|
||||||
|
{
|
||||||
|
var chartMaps = []maps.Map{}
|
||||||
|
for _, chart := range resp.MetricDataCharts {
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range chart.MetricStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"keys": stat.Keys,
|
||||||
|
"time": stat.Time,
|
||||||
|
"value": stat.Value,
|
||||||
|
"count": stat.SumCount,
|
||||||
|
"total": stat.SumTotal,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
chartMaps = append(chartMaps, maps.Map{
|
||||||
|
"chart": maps.Map{
|
||||||
|
"id": chart.MetricChart.Id,
|
||||||
|
"name": chart.MetricChart.Name,
|
||||||
|
"widthDiv": chart.MetricChart.WidthDiv,
|
||||||
|
"isOn": chart.MetricChart.IsOn,
|
||||||
|
"maxItems": chart.MetricChart.MaxItems,
|
||||||
|
"type": chart.MetricChart.Type,
|
||||||
|
},
|
||||||
|
"item": maps.Map{
|
||||||
|
"id": chart.MetricChart.MetricItem.Id,
|
||||||
|
"name": chart.MetricChart.MetricItem.Name,
|
||||||
|
"period": chart.MetricChart.MetricItem.Period,
|
||||||
|
"periodUnit": chart.MetricChart.MetricItem.PeriodUnit,
|
||||||
|
"valueType": serverconfigs.FindMetricValueType(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||||
|
"valueTypeName": serverconfigs.FindMetricValueName(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||||
|
"keys": chart.MetricChart.MetricItem.Keys,
|
||||||
|
},
|
||||||
|
"stats": statMaps,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["metricCharts"] = chartMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
package cluster
|
package cluster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"fmt"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/logs"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
"github.com/iwind/TeaGo/types"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -18,207 +13,15 @@ type IndexAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) Init() {
|
func (this *IndexAction) Init() {
|
||||||
this.Nav("", "node", "index")
|
this.Nav("", "", "")
|
||||||
this.SecondMenu("nodes")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct {
|
func (this *IndexAction) RunGet(params struct {
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
GroupId int64
|
|
||||||
RegionId int64
|
|
||||||
InstalledState int
|
|
||||||
ActiveState int
|
|
||||||
Keyword string
|
|
||||||
}) {
|
}) {
|
||||||
this.Data["groupId"] = params.GroupId
|
if teaconst.IsPlus {
|
||||||
this.Data["regionId"] = params.RegionId
|
this.RedirectURL("/clusters/cluster/boards?clusterId=" + strconv.FormatInt(params.ClusterId, 10))
|
||||||
this.Data["installState"] = params.InstalledState
|
} else {
|
||||||
this.Data["activeState"] = params.ActiveState
|
this.RedirectURL("/clusters/cluster/nodes?clusterId=" + strconv.FormatInt(params.ClusterId, 10))
|
||||||
this.Data["keyword"] = params.Keyword
|
|
||||||
|
|
||||||
countAllResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
|
||||||
NodeClusterId: params.ClusterId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
this.Data["countAll"] = countAllResp.Count
|
|
||||||
|
|
||||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
|
||||||
NodeClusterId: params.ClusterId,
|
|
||||||
NodeGroupId: params.GroupId,
|
|
||||||
NodeRegionId: params.RegionId,
|
|
||||||
InstallState: types.Int32(params.InstalledState),
|
|
||||||
ActiveState: types.Int32(params.ActiveState),
|
|
||||||
Keyword: params.Keyword,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page := this.NewPage(countResp.Count)
|
|
||||||
this.Data["page"] = page.AsHTML()
|
|
||||||
|
|
||||||
nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), &pb.ListEnabledNodesMatchRequest{
|
|
||||||
Offset: page.Offset,
|
|
||||||
Size: page.Size,
|
|
||||||
NodeClusterId: params.ClusterId,
|
|
||||||
NodeGroupId: params.GroupId,
|
|
||||||
NodeRegionId: params.RegionId,
|
|
||||||
InstallState: types.Int32(params.InstalledState),
|
|
||||||
ActiveState: types.Int32(params.ActiveState),
|
|
||||||
Keyword: params.Keyword,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nodeMaps := []maps.Map{}
|
|
||||||
for _, node := range nodesResp.Nodes {
|
|
||||||
// 状态
|
|
||||||
isSynced := false
|
|
||||||
status := &nodeconfigs.NodeStatus{}
|
|
||||||
if len(node.StatusJSON) > 0 {
|
|
||||||
err = json.Unmarshal(node.StatusJSON, &status)
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
|
||||||
isSynced = status.ConfigVersion == node.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
// IP
|
|
||||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
|
|
||||||
NodeId: node.Id,
|
|
||||||
Role: nodeconfigs.NodeRoleNode,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ipAddresses := []maps.Map{}
|
|
||||||
for _, addr := range ipAddressesResp.Addresses {
|
|
||||||
ipAddresses = append(ipAddresses, maps.Map{
|
|
||||||
"id": addr.Id,
|
|
||||||
"name": addr.Name,
|
|
||||||
"ip": addr.Ip,
|
|
||||||
"canAccess": addr.CanAccess,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分组
|
|
||||||
var groupMap maps.Map = nil
|
|
||||||
if node.NodeGroup != nil {
|
|
||||||
groupMap = maps.Map{
|
|
||||||
"id": node.NodeGroup.Id,
|
|
||||||
"name": node.NodeGroup.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 区域
|
|
||||||
var regionMap maps.Map = nil
|
|
||||||
if node.NodeRegion != nil {
|
|
||||||
regionMap = maps.Map{
|
|
||||||
"id": node.NodeRegion.Id,
|
|
||||||
"name": node.NodeRegion.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DNS
|
|
||||||
dnsRouteNames := []string{}
|
|
||||||
for _, route := range node.DnsRoutes {
|
|
||||||
dnsRouteNames = append(dnsRouteNames, route.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeMaps = append(nodeMaps, maps.Map{
|
|
||||||
"id": node.Id,
|
|
||||||
"name": node.Name,
|
|
||||||
"isInstalled": node.IsInstalled,
|
|
||||||
"isOn": node.IsOn,
|
|
||||||
"isUp": node.IsUp,
|
|
||||||
"installStatus": maps.Map{
|
|
||||||
"isRunning": node.InstallStatus.IsRunning,
|
|
||||||
"isFinished": node.InstallStatus.IsFinished,
|
|
||||||
"isOk": node.InstallStatus.IsOk,
|
|
||||||
"error": node.InstallStatus.Error,
|
|
||||||
},
|
|
||||||
"status": maps.Map{
|
|
||||||
"isActive": status.IsActive,
|
|
||||||
"updatedAt": status.UpdatedAt,
|
|
||||||
"hostname": status.Hostname,
|
|
||||||
"cpuUsage": status.CPUUsage,
|
|
||||||
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
|
||||||
"memUsage": status.MemoryUsage,
|
|
||||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
|
||||||
},
|
|
||||||
"cluster": maps.Map{
|
|
||||||
"id": node.NodeCluster.Id,
|
|
||||||
"name": node.NodeCluster.Name,
|
|
||||||
},
|
|
||||||
"isSynced": isSynced,
|
|
||||||
"ipAddresses": ipAddresses,
|
|
||||||
"group": groupMap,
|
|
||||||
"region": regionMap,
|
|
||||||
"dnsRouteNames": dnsRouteNames,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["nodes"] = nodeMaps
|
|
||||||
|
|
||||||
// 所有分组
|
|
||||||
groupMaps := []maps.Map{}
|
|
||||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{
|
|
||||||
NodeClusterId: params.ClusterId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, group := range groupsResp.NodeGroups {
|
|
||||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{NodeGroupId: group.Id})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
countNodes := countResp.Count
|
|
||||||
groupName := group.Name
|
|
||||||
if countNodes > 0 {
|
|
||||||
groupName += "(" + strconv.FormatInt(countNodes, 10) + ")"
|
|
||||||
}
|
|
||||||
groupMaps = append(groupMaps, maps.Map{
|
|
||||||
"id": group.Id,
|
|
||||||
"name": groupName,
|
|
||||||
"countNodes": countNodes,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["groups"] = groupMaps
|
|
||||||
|
|
||||||
// 所有区域
|
|
||||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
regionMaps := []maps.Map{}
|
|
||||||
for _, region := range regionsResp.NodeRegions {
|
|
||||||
regionMaps = append(regionMaps, maps.Map{
|
|
||||||
"id": region.Id,
|
|
||||||
"name": region.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["regions"] = regionMaps
|
|
||||||
|
|
||||||
// 记录最近访问
|
|
||||||
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
|
||||||
ItemType: "cluster",
|
|
||||||
ItemId: params.ClusterId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Show()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ package cluster
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/boards"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/groups"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/groups"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/monitor"
|
nodeboards "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/boards"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/thresholds"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/thresholds"
|
||||||
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
@@ -18,6 +19,7 @@ func init() {
|
|||||||
Helper(clusters.NewClusterHelper()).
|
Helper(clusters.NewClusterHelper()).
|
||||||
Prefix("/clusters/cluster").
|
Prefix("/clusters/cluster").
|
||||||
Get("", new(IndexAction)).
|
Get("", new(IndexAction)).
|
||||||
|
Get("/nodes", new(NodesAction)).
|
||||||
GetPost("/installNodes", new(InstallNodesAction)).
|
GetPost("/installNodes", new(InstallNodesAction)).
|
||||||
GetPost("/installRemote", new(InstallRemoteAction)).
|
GetPost("/installRemote", new(InstallRemoteAction)).
|
||||||
Post("/installStatus", new(InstallStatusAction)).
|
Post("/installStatus", new(InstallStatusAction)).
|
||||||
@@ -30,31 +32,32 @@ func init() {
|
|||||||
GetPost("/installManual", new(InstallManualAction)).
|
GetPost("/installManual", new(InstallManualAction)).
|
||||||
|
|
||||||
// 节点相关
|
// 节点相关
|
||||||
Get("/node", new(node.IndexAction)).
|
Prefix("/clusters/cluster/node").
|
||||||
GetPost("/node/update", new(node.UpdateAction)).
|
Get("", new(node.IndexAction)).
|
||||||
GetPost("/node/install", new(node.InstallAction)).
|
GetPost("/update", new(node.UpdateAction)).
|
||||||
Post("/node/updateInstallStatus", new(node.UpdateInstallStatusAction)).
|
GetPost("/install", new(node.InstallAction)).
|
||||||
Post("/node/status", new(node.StatusAction)).
|
Post("/updateInstallStatus", new(node.UpdateInstallStatusAction)).
|
||||||
Get("/node/logs", new(node.LogsAction)).
|
Post("/status", new(node.StatusAction)).
|
||||||
Post("/node/start", new(node.StartAction)).
|
Get("/logs", new(node.LogsAction)).
|
||||||
Post("/node/stop", new(node.StopAction)).
|
Post("/start", new(node.StartAction)).
|
||||||
Post("/node/up", new(node.UpAction)).
|
Post("/stop", new(node.StopAction)).
|
||||||
Get("/node/monitor", new(monitor.IndexAction)).
|
Post("/up", new(node.UpAction)).
|
||||||
Post("/node/monitor/cpu", new(monitor.CpuAction)).
|
Get("/thresholds", new(thresholds.IndexAction)).
|
||||||
Post("/node/monitor/memory", new(monitor.MemoryAction)).
|
Get("/detail", new(node.DetailAction)).
|
||||||
Post("/node/monitor/load", new(monitor.LoadAction)).
|
GetPost("/boards", new(nodeboards.IndexAction)).
|
||||||
Post("/node/monitor/trafficIn", new(monitor.TrafficInAction)).
|
|
||||||
Post("/node/monitor/trafficOut", new(monitor.TrafficOutAction)).
|
|
||||||
Post("/node/monitor/connections", new(monitor.ConnectionsAction)).
|
|
||||||
Get("/node/thresholds", new(thresholds.IndexAction)).
|
|
||||||
|
|
||||||
// 分组相关
|
// 分组相关
|
||||||
Get("/groups", new(groups.IndexAction)).
|
Prefix("/clusters/cluster/groups").
|
||||||
GetPost("/groups/createPopup", new(groups.CreatePopupAction)).
|
Get("", new(groups.IndexAction)).
|
||||||
GetPost("/groups/updatePopup", new(groups.UpdatePopupAction)).
|
GetPost("/createPopup", new(groups.CreatePopupAction)).
|
||||||
Post("/groups/delete", new(groups.DeleteAction)).
|
GetPost("/updatePopup", new(groups.UpdatePopupAction)).
|
||||||
Post("/groups/sort", new(groups.SortAction)).
|
Post("/delete", new(groups.DeleteAction)).
|
||||||
GetPost("/groups/selectPopup", new(groups.SelectPopupAction)).
|
Post("/sort", new(groups.SortAction)).
|
||||||
|
GetPost("/selectPopup", new(groups.SelectPopupAction)).
|
||||||
|
|
||||||
|
// 看板相关
|
||||||
|
Prefix("/clusters/cluster/boards").
|
||||||
|
Get("", new(boards.IndexAction)).
|
||||||
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,232 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package boards
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "node", "board")
|
||||||
|
this.SecondMenu("nodes")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
NodeId int64
|
||||||
|
}) {
|
||||||
|
err := nodeutils.InitNodeInfo(this, params.NodeId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !teaconst.IsPlus {
|
||||||
|
this.RedirectURL("/clusters/cluster/node?clusterId=" + strconv.FormatInt(params.ClusterId, 10) + "&nodeId=" + strconv.FormatInt(params.NodeId, 10))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := this.RPC().ServerStatBoardRPC().ComposeServerStatNodeBoard(this.AdminContext(), &pb.ComposeServerStatNodeBoardRequest{NodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["board"] = maps.Map{
|
||||||
|
"isActive": resp.IsActive,
|
||||||
|
"trafficInBytes": resp.TrafficInBytes,
|
||||||
|
"trafficOutBytes": resp.TrafficOutBytes,
|
||||||
|
"countConnections": resp.CountConnections,
|
||||||
|
"countRequests": resp.CountRequests,
|
||||||
|
"countAttackRequests": resp.CountAttackRequests,
|
||||||
|
"cpuUsage": resp.CpuUsage,
|
||||||
|
"memoryUsage": resp.MemoryUsage,
|
||||||
|
"memoryTotalSize": resp.MemoryTotalSize,
|
||||||
|
"load": resp.Load,
|
||||||
|
"cacheDiskSize": resp.CacheDiskSize,
|
||||||
|
"cacheMemorySize": resp.CacheMemorySize,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 24小时流量趋势
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.HourlyTrafficStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
"cachedBytes": stat.CachedBytes,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"countCachedRequests": stat.CountCachedRequests,
|
||||||
|
"countAttackRequests": stat.CountAttackRequests,
|
||||||
|
"attackBytes": stat.AttackBytes,
|
||||||
|
"day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
|
||||||
|
"hour": stat.Hour[8:],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["hourlyStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 15天流量趋势
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.DailyTrafficStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
"cachedBytes": stat.CachedBytes,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"countCachedRequests": stat.CountCachedRequests,
|
||||||
|
"countAttackRequests": stat.CountAttackRequests,
|
||||||
|
"attackBytes": stat.AttackBytes,
|
||||||
|
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["dailyStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 域名排行
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.TopDomainStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"serverId": stat.ServerId,
|
||||||
|
"domain": stat.Domain,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["topDomainStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPU
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.CpuNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["cpuValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.MemoryNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["memoryValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.LoadNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["loadValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// CacheDirs
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.CacheDirsValues {
|
||||||
|
var m = maps.Map{}
|
||||||
|
err = json.Unmarshal(stat.ValueJSON, &m)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": m,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["cacheDirValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指标
|
||||||
|
{
|
||||||
|
var chartMaps = []maps.Map{}
|
||||||
|
for _, chart := range resp.MetricDataCharts {
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range chart.MetricStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"keys": stat.Keys,
|
||||||
|
"time": stat.Time,
|
||||||
|
"value": stat.Value,
|
||||||
|
"count": stat.SumCount,
|
||||||
|
"total": stat.SumTotal,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
chartMaps = append(chartMaps, maps.Map{
|
||||||
|
"chart": maps.Map{
|
||||||
|
"id": chart.MetricChart.Id,
|
||||||
|
"name": chart.MetricChart.Name,
|
||||||
|
"widthDiv": chart.MetricChart.WidthDiv,
|
||||||
|
"isOn": chart.MetricChart.IsOn,
|
||||||
|
"maxItems": chart.MetricChart.MaxItems,
|
||||||
|
"type": chart.MetricChart.Type,
|
||||||
|
},
|
||||||
|
"item": maps.Map{
|
||||||
|
"id": chart.MetricChart.MetricItem.Id,
|
||||||
|
"name": chart.MetricChart.MetricItem.Name,
|
||||||
|
"period": chart.MetricChart.MetricItem.Period,
|
||||||
|
"periodUnit": chart.MetricChart.MetricItem.PeriodUnit,
|
||||||
|
"valueType": serverconfigs.FindMetricValueType(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||||
|
"valueTypeName": serverconfigs.FindMetricValueName(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||||
|
"keys": chart.MetricChart.MetricItem.Keys,
|
||||||
|
},
|
||||||
|
"stats": statMaps,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["metricCharts"] = chartMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunPost(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
NodeId int64
|
||||||
|
}) {
|
||||||
|
resp, err := this.RPC().ServerStatBoardRPC().ComposeServerStatNodeBoard(this.AdminContext(), &pb.ComposeServerStatNodeBoardRequest{NodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["board"] = maps.Map{
|
||||||
|
"isActive": resp.IsActive,
|
||||||
|
"trafficInBytes": resp.TrafficInBytes,
|
||||||
|
"trafficOutBytes": resp.TrafficOutBytes,
|
||||||
|
"countConnections": resp.CountConnections,
|
||||||
|
"countRequests": resp.CountRequests,
|
||||||
|
"countAttackRequests": resp.CountAttackRequests,
|
||||||
|
"cpuUsage": resp.CpuUsage,
|
||||||
|
"memoryUsage": resp.MemoryUsage,
|
||||||
|
"memoryTotalSize": resp.MemoryTotalSize,
|
||||||
|
"load": resp.Load,
|
||||||
|
"cacheDiskSize": resp.CacheDiskSize,
|
||||||
|
"cacheMemorySize": resp.CacheMemorySize,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
259
internal/web/actions/default/clusters/cluster/node/detail.go
Normal file
259
internal/web/actions/default/clusters/cluster/node/detail.go
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DetailAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DetailAction) Init() {
|
||||||
|
this.Nav("", "node", "node")
|
||||||
|
this.SecondMenu("nodes")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DetailAction) RunGet(params struct {
|
||||||
|
NodeId int64
|
||||||
|
}) {
|
||||||
|
this.Data["nodeId"] = params.NodeId
|
||||||
|
|
||||||
|
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node := nodeResp.Node
|
||||||
|
if node == nil {
|
||||||
|
this.WriteString("找不到要操作的节点")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var clusterMap maps.Map = nil
|
||||||
|
if node.NodeCluster != nil {
|
||||||
|
clusterId := node.NodeCluster.Id
|
||||||
|
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: clusterId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cluster := clusterResp.NodeCluster
|
||||||
|
if cluster != nil {
|
||||||
|
clusterMap = maps.Map{
|
||||||
|
"id": cluster.Id,
|
||||||
|
"name": cluster.Name,
|
||||||
|
"installDir": cluster.InstallDir,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IP地址
|
||||||
|
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
|
||||||
|
NodeId: params.NodeId,
|
||||||
|
Role: nodeconfigs.NodeRoleNode,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ipAddressMaps := []maps.Map{}
|
||||||
|
for _, addr := range ipAddressesResp.Addresses {
|
||||||
|
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
||||||
|
"id": addr.Id,
|
||||||
|
"name": addr.Name,
|
||||||
|
"ip": addr.Ip,
|
||||||
|
"canAccess": addr.CanAccess,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNS相关
|
||||||
|
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{NodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dnsRouteMaps := []maps.Map{}
|
||||||
|
recordName := ""
|
||||||
|
recordValue := ""
|
||||||
|
if dnsInfoResp.Node != nil {
|
||||||
|
recordName = dnsInfoResp.Node.NodeClusterDNSName + "." + dnsInfoResp.Node.DnsDomainName
|
||||||
|
recordValue = dnsInfoResp.Node.IpAddr
|
||||||
|
for _, dnsInfo := range dnsInfoResp.Node.Routes {
|
||||||
|
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
||||||
|
"name": dnsInfo.Name,
|
||||||
|
"code": dnsInfo.Code,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
if node.Login != nil {
|
||||||
|
loginParams := maps.Map{}
|
||||||
|
if len(node.Login.Params) > 0 {
|
||||||
|
err = json.Unmarshal(node.Login.Params, &loginParams)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grantMap := maps.Map{}
|
||||||
|
grantId := loginParams.GetInt64("grantId")
|
||||||
|
if grantId > 0 {
|
||||||
|
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if grantResp.NodeGrant != nil {
|
||||||
|
grantMap = maps.Map{
|
||||||
|
"id": grantResp.NodeGrant.Id,
|
||||||
|
"name": grantResp.NodeGrant.Name,
|
||||||
|
"method": grantResp.NodeGrant.Method,
|
||||||
|
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loginMap = maps.Map{
|
||||||
|
"id": node.Login.Id,
|
||||||
|
"name": node.Login.Name,
|
||||||
|
"type": node.Login.Type,
|
||||||
|
"params": loginParams,
|
||||||
|
"grant": grantMap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 运行状态
|
||||||
|
status := &nodeconfigs.NodeStatus{}
|
||||||
|
if len(node.StatusJSON) > 0 {
|
||||||
|
err = json.Unmarshal(node.StatusJSON, &status)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有新版本
|
||||||
|
if len(status.OS) > 0 {
|
||||||
|
checkVersionResp, err := this.RPC().NodeRPC().CheckNodeLatestVersion(this.AdminContext(), &pb.CheckNodeLatestVersionRequest{
|
||||||
|
Os: status.OS,
|
||||||
|
Arch: status.Arch,
|
||||||
|
CurrentVersion: status.BuildVersion,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["shouldUpgrade"] = checkVersionResp.HasNewVersion
|
||||||
|
this.Data["newVersion"] = checkVersionResp.NewVersion
|
||||||
|
} else {
|
||||||
|
this.Data["shouldUpgrade"] = false
|
||||||
|
this.Data["newVersion"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分组
|
||||||
|
var groupMap maps.Map = nil
|
||||||
|
if node.NodeGroup != nil {
|
||||||
|
groupMap = maps.Map{
|
||||||
|
"id": node.NodeGroup.Id,
|
||||||
|
"name": node.NodeGroup.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 区域
|
||||||
|
var regionMap maps.Map = nil
|
||||||
|
if node.NodeRegion != nil {
|
||||||
|
regionMap = maps.Map{
|
||||||
|
"id": node.NodeRegion.Id,
|
||||||
|
"name": node.NodeRegion.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缓存硬盘 & 内存容量
|
||||||
|
var maxCacheDiskCapacity maps.Map = nil
|
||||||
|
if node.MaxCacheDiskCapacity != nil {
|
||||||
|
maxCacheDiskCapacity = maps.Map{
|
||||||
|
"count": node.MaxCacheDiskCapacity.Count,
|
||||||
|
"unit": node.MaxCacheDiskCapacity.Unit,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
maxCacheDiskCapacity = maps.Map{
|
||||||
|
"count": 0,
|
||||||
|
"unit": "gb",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxCacheMemoryCapacity maps.Map = nil
|
||||||
|
if node.MaxCacheMemoryCapacity != nil {
|
||||||
|
maxCacheMemoryCapacity = maps.Map{
|
||||||
|
"count": node.MaxCacheMemoryCapacity.Count,
|
||||||
|
"unit": node.MaxCacheMemoryCapacity.Unit,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
maxCacheMemoryCapacity = maps.Map{
|
||||||
|
"count": 0,
|
||||||
|
"unit": "gb",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["node"] = maps.Map{
|
||||||
|
"id": node.Id,
|
||||||
|
"name": node.Name,
|
||||||
|
"ipAddresses": ipAddressMaps,
|
||||||
|
"cluster": clusterMap,
|
||||||
|
"login": loginMap,
|
||||||
|
"installDir": node.InstallDir,
|
||||||
|
"isInstalled": node.IsInstalled,
|
||||||
|
"uniqueId": node.UniqueId,
|
||||||
|
"secret": node.Secret,
|
||||||
|
"maxCPU": node.MaxCPU,
|
||||||
|
"isOn": node.IsOn,
|
||||||
|
|
||||||
|
"status": maps.Map{
|
||||||
|
"isActive": status.IsActive,
|
||||||
|
"updatedAt": status.UpdatedAt,
|
||||||
|
"hostname": status.Hostname,
|
||||||
|
"cpuUsage": status.CPUUsage,
|
||||||
|
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
||||||
|
"memUsage": status.MemoryUsage,
|
||||||
|
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||||
|
"connectionCount": status.ConnectionCount,
|
||||||
|
"buildVersion": status.BuildVersion,
|
||||||
|
"cpuPhysicalCount": status.CPUPhysicalCount,
|
||||||
|
"cpuLogicalCount": status.CPULogicalCount,
|
||||||
|
"load1m": fmt.Sprintf("%.2f", status.Load1m),
|
||||||
|
"load5m": fmt.Sprintf("%.2f", status.Load5m),
|
||||||
|
"load15m": fmt.Sprintf("%.2f", status.Load15m),
|
||||||
|
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
|
||||||
|
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
|
||||||
|
},
|
||||||
|
|
||||||
|
"group": groupMap,
|
||||||
|
"region": regionMap,
|
||||||
|
|
||||||
|
"maxCacheDiskCapacity": maxCacheDiskCapacity,
|
||||||
|
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"strconv"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -24,236 +20,15 @@ func (this *IndexAction) Init() {
|
|||||||
func (this *IndexAction) RunGet(params struct {
|
func (this *IndexAction) RunGet(params struct {
|
||||||
NodeId int64
|
NodeId int64
|
||||||
}) {
|
}) {
|
||||||
this.Data["nodeId"] = params.NodeId
|
err := nodeutils.InitNodeInfo(this, params.NodeId)
|
||||||
|
|
||||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
node := nodeResp.Node
|
|
||||||
if node == nil {
|
|
||||||
this.WriteString("找不到要操作的节点")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var clusterMap maps.Map = nil
|
if teaconst.IsPlus {
|
||||||
if node.NodeCluster != nil {
|
this.RedirectURL("/clusters/cluster/node/boards?clusterId=" + fmt.Sprintf("%d", this.Data["clusterId"]) + "&nodeId=" + strconv.FormatInt(params.NodeId, 10))
|
||||||
clusterId := node.NodeCluster.Id
|
|
||||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: clusterId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cluster := clusterResp.NodeCluster
|
|
||||||
if cluster != nil {
|
|
||||||
clusterMap = maps.Map{
|
|
||||||
"id": cluster.Id,
|
|
||||||
"name": cluster.Name,
|
|
||||||
"installDir": cluster.InstallDir,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IP地址
|
|
||||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
|
|
||||||
NodeId: params.NodeId,
|
|
||||||
Role: nodeconfigs.NodeRoleNode,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ipAddressMaps := []maps.Map{}
|
|
||||||
for _, addr := range ipAddressesResp.Addresses {
|
|
||||||
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
|
||||||
"id": addr.Id,
|
|
||||||
"name": addr.Name,
|
|
||||||
"ip": addr.Ip,
|
|
||||||
"canAccess": addr.CanAccess,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// DNS相关
|
|
||||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{NodeId: params.NodeId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dnsRouteMaps := []maps.Map{}
|
|
||||||
recordName := ""
|
|
||||||
recordValue := ""
|
|
||||||
if dnsInfoResp.Node != nil {
|
|
||||||
recordName = dnsInfoResp.Node.NodeClusterDNSName + "." + dnsInfoResp.Node.DnsDomainName
|
|
||||||
recordValue = dnsInfoResp.Node.IpAddr
|
|
||||||
for _, dnsInfo := range dnsInfoResp.Node.Routes {
|
|
||||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
|
||||||
"name": dnsInfo.Name,
|
|
||||||
"code": dnsInfo.Code,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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
|
|
||||||
if node.Login != nil {
|
|
||||||
loginParams := maps.Map{}
|
|
||||||
if len(node.Login.Params) > 0 {
|
|
||||||
err = json.Unmarshal(node.Login.Params, &loginParams)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
grantMap := maps.Map{}
|
|
||||||
grantId := loginParams.GetInt64("grantId")
|
|
||||||
if grantId > 0 {
|
|
||||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if grantResp.NodeGrant != nil {
|
|
||||||
grantMap = maps.Map{
|
|
||||||
"id": grantResp.NodeGrant.Id,
|
|
||||||
"name": grantResp.NodeGrant.Name,
|
|
||||||
"method": grantResp.NodeGrant.Method,
|
|
||||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loginMap = maps.Map{
|
|
||||||
"id": node.Login.Id,
|
|
||||||
"name": node.Login.Name,
|
|
||||||
"type": node.Login.Type,
|
|
||||||
"params": loginParams,
|
|
||||||
"grant": grantMap,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 运行状态
|
|
||||||
status := &nodeconfigs.NodeStatus{}
|
|
||||||
if len(node.StatusJSON) > 0 {
|
|
||||||
err = json.Unmarshal(node.StatusJSON, &status)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否有新版本
|
|
||||||
if len(status.OS) > 0 {
|
|
||||||
checkVersionResp, err := this.RPC().NodeRPC().CheckNodeLatestVersion(this.AdminContext(), &pb.CheckNodeLatestVersionRequest{
|
|
||||||
Os: status.OS,
|
|
||||||
Arch: status.Arch,
|
|
||||||
CurrentVersion: status.BuildVersion,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.Data["shouldUpgrade"] = checkVersionResp.HasNewVersion
|
|
||||||
this.Data["newVersion"] = checkVersionResp.NewVersion
|
|
||||||
} else {
|
} else {
|
||||||
this.Data["shouldUpgrade"] = false
|
this.RedirectURL("/clusters/cluster/node/detail?clusterId=" + fmt.Sprintf("%d", this.Data["clusterId"]) + strconv.FormatInt(params.NodeId, 10))
|
||||||
this.Data["newVersion"] = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分组
|
|
||||||
var groupMap maps.Map = nil
|
|
||||||
if node.NodeGroup != nil {
|
|
||||||
groupMap = maps.Map{
|
|
||||||
"id": node.NodeGroup.Id,
|
|
||||||
"name": node.NodeGroup.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 区域
|
|
||||||
var regionMap maps.Map = nil
|
|
||||||
if node.NodeRegion != nil {
|
|
||||||
regionMap = maps.Map{
|
|
||||||
"id": node.NodeRegion.Id,
|
|
||||||
"name": node.NodeRegion.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 缓存硬盘 & 内存容量
|
|
||||||
var maxCacheDiskCapacity maps.Map = nil
|
|
||||||
if node.MaxCacheDiskCapacity != nil {
|
|
||||||
maxCacheDiskCapacity = maps.Map{
|
|
||||||
"count": node.MaxCacheDiskCapacity.Count,
|
|
||||||
"unit": node.MaxCacheDiskCapacity.Unit,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
maxCacheDiskCapacity = maps.Map{
|
|
||||||
"count": 0,
|
|
||||||
"unit": "gb",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var maxCacheMemoryCapacity maps.Map = nil
|
|
||||||
if node.MaxCacheMemoryCapacity != nil {
|
|
||||||
maxCacheMemoryCapacity = maps.Map{
|
|
||||||
"count": node.MaxCacheMemoryCapacity.Count,
|
|
||||||
"unit": node.MaxCacheMemoryCapacity.Unit,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
maxCacheMemoryCapacity = maps.Map{
|
|
||||||
"count": 0,
|
|
||||||
"unit": "gb",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
|
||||||
"id": node.Id,
|
|
||||||
"name": node.Name,
|
|
||||||
"ipAddresses": ipAddressMaps,
|
|
||||||
"cluster": clusterMap,
|
|
||||||
"login": loginMap,
|
|
||||||
"installDir": node.InstallDir,
|
|
||||||
"isInstalled": node.IsInstalled,
|
|
||||||
"uniqueId": node.UniqueId,
|
|
||||||
"secret": node.Secret,
|
|
||||||
"maxCPU": node.MaxCPU,
|
|
||||||
"isOn": node.IsOn,
|
|
||||||
|
|
||||||
"status": maps.Map{
|
|
||||||
"isActive": status.IsActive,
|
|
||||||
"updatedAt": status.UpdatedAt,
|
|
||||||
"hostname": status.Hostname,
|
|
||||||
"cpuUsage": status.CPUUsage,
|
|
||||||
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
|
||||||
"memUsage": status.MemoryUsage,
|
|
||||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
|
||||||
"connectionCount": status.ConnectionCount,
|
|
||||||
"buildVersion": status.BuildVersion,
|
|
||||||
"cpuPhysicalCount": status.CPUPhysicalCount,
|
|
||||||
"cpuLogicalCount": status.CPULogicalCount,
|
|
||||||
"load1m": fmt.Sprintf("%.2f", status.Load1m),
|
|
||||||
"load5m": fmt.Sprintf("%.2f", status.Load5m),
|
|
||||||
"load15m": fmt.Sprintf("%.2f", status.Load15m),
|
|
||||||
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
|
|
||||||
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
|
|
||||||
},
|
|
||||||
|
|
||||||
"group": groupMap,
|
|
||||||
"region": regionMap,
|
|
||||||
|
|
||||||
"maxCacheDiskCapacity": maxCacheDiskCapacity,
|
|
||||||
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Show()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package node
|
|||||||
|
|
||||||
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/clusters/cluster/node/nodeutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
@@ -23,6 +24,13 @@ func (this *LogsAction) RunGet(params struct {
|
|||||||
Keyword string
|
Keyword string
|
||||||
Level string
|
Level string
|
||||||
}) {
|
}) {
|
||||||
|
// 初始化节点信息(用于菜单)
|
||||||
|
err := nodeutils.InitNodeInfo(this, params.NodeId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["nodeId"] = params.NodeId
|
this.Data["nodeId"] = params.NodeId
|
||||||
this.Data["dayFrom"] = params.DayFrom
|
this.Data["dayFrom"] = params.DayFrom
|
||||||
this.Data["dayTo"] = params.DayTo
|
this.Data["dayTo"] = params.DayTo
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
|
||||||
|
|
||||||
package monitor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ConnectionsAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *ConnectionsAction) RunPost(params struct {
|
|
||||||
NodeId int64
|
|
||||||
}) {
|
|
||||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
|
||||||
Role: "node",
|
|
||||||
NodeId: params.NodeId,
|
|
||||||
Item: nodeconfigs.NodeValueItemConnections,
|
|
||||||
Range: nodeconfigs.NodeValueRangeMinute,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
valuesMap := map[string]int64{} // YmdHi => count
|
|
||||||
for _, v := range resp.NodeValues {
|
|
||||||
if len(v.ValueJSON) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
valueMap := maps.Map{}
|
|
||||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetInt64("total")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过去一个小时
|
|
||||||
result := []maps.Map{}
|
|
||||||
for i := 60; i >= 1; i-- {
|
|
||||||
timestamp := time.Now().Unix() - int64(i)*60
|
|
||||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
|
||||||
total, ok := valuesMap[minute]
|
|
||||||
if ok {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": total,
|
|
||||||
"text": numberutils.FormatInt64(total),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": 0,
|
|
||||||
"text": "0",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["values"] = result
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
|
||||||
|
|
||||||
package monitor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CpuAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *CpuAction) RunPost(params struct {
|
|
||||||
NodeId int64
|
|
||||||
}) {
|
|
||||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
|
||||||
Role: "node",
|
|
||||||
NodeId: params.NodeId,
|
|
||||||
Item: nodeconfigs.NodeValueItemCPU,
|
|
||||||
Range: nodeconfigs.NodeValueRangeMinute,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
valuesMap := map[string]float32{} // YmdHi => usage
|
|
||||||
for _, v := range resp.NodeValues {
|
|
||||||
if len(v.ValueJSON) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
valueMap := maps.Map{}
|
|
||||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetFloat32("usage") * 100
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过去一个小时
|
|
||||||
result := []maps.Map{}
|
|
||||||
for i := 60; i >= 1; i-- {
|
|
||||||
timestamp := time.Now().Unix() - int64(i)*60
|
|
||||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
|
||||||
total, ok := valuesMap[minute]
|
|
||||||
if ok {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": total,
|
|
||||||
"text": fmt.Sprintf("%.2f%%", total),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": 0,
|
|
||||||
"text": "0.0%",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["values"] = result
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
|
||||||
|
|
||||||
package monitor
|
|
||||||
|
|
||||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
|
|
||||||
type IndexAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *IndexAction) Init() {
|
|
||||||
this.Nav("", "node", "monitor")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct {
|
|
||||||
NodeId int64
|
|
||||||
}) {
|
|
||||||
this.Data["nodeId"] = params.NodeId
|
|
||||||
|
|
||||||
this.Show()
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
|
||||||
|
|
||||||
package monitor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LoadAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *LoadAction) RunPost(params struct {
|
|
||||||
NodeId int64
|
|
||||||
}) {
|
|
||||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
|
||||||
Role: "node",
|
|
||||||
NodeId: params.NodeId,
|
|
||||||
Item: nodeconfigs.NodeValueItemLoad,
|
|
||||||
Range: nodeconfigs.NodeValueRangeMinute,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
valuesMap := map[string]float32{} // YmdHi => load5m
|
|
||||||
for _, v := range resp.NodeValues {
|
|
||||||
if len(v.ValueJSON) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
valueMap := maps.Map{}
|
|
||||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetFloat32("load5m")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过去一个小时
|
|
||||||
result := []maps.Map{}
|
|
||||||
for i := 60; i >= 1; i-- {
|
|
||||||
timestamp := time.Now().Unix() - int64(i)*60
|
|
||||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
|
||||||
total, ok := valuesMap[minute]
|
|
||||||
if ok {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": total,
|
|
||||||
"text": fmt.Sprintf("5分钟: %.2f", total),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": 0,
|
|
||||||
"text": "5分钟: 0.0",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["values"] = result
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
|
||||||
|
|
||||||
package monitor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MemoryAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *MemoryAction) RunPost(params struct {
|
|
||||||
NodeId int64
|
|
||||||
}) {
|
|
||||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
|
||||||
Role: "node",
|
|
||||||
NodeId: params.NodeId,
|
|
||||||
Item: nodeconfigs.NodeValueItemMemory,
|
|
||||||
Range: nodeconfigs.NodeValueRangeMinute,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
valuesMap := map[string]float32{} // YmdHi => usage
|
|
||||||
for _, v := range resp.NodeValues {
|
|
||||||
if len(v.ValueJSON) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
valueMap := maps.Map{}
|
|
||||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetFloat32("usage") * 100
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过去一个小时
|
|
||||||
result := []maps.Map{}
|
|
||||||
for i := 60; i >= 1; i-- {
|
|
||||||
timestamp := time.Now().Unix() - int64(i)*60
|
|
||||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
|
||||||
total, ok := valuesMap[minute]
|
|
||||||
if ok {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": total,
|
|
||||||
"text": fmt.Sprintf("%.2f%%", total),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": 0,
|
|
||||||
"text": "0.0%",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["values"] = result
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
|
||||||
|
|
||||||
package monitor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TrafficInAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *TrafficInAction) RunPost(params struct {
|
|
||||||
NodeId int64
|
|
||||||
}) {
|
|
||||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
|
||||||
Role: "node",
|
|
||||||
NodeId: params.NodeId,
|
|
||||||
Item: nodeconfigs.NodeValueItemTrafficIn,
|
|
||||||
Range: nodeconfigs.NodeValueRangeMinute,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
valuesMap := map[string]int64{} // YmdHi => bytes
|
|
||||||
for _, v := range resp.NodeValues {
|
|
||||||
if len(v.ValueJSON) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
valueMap := maps.Map{}
|
|
||||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetInt64("total")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过去一个小时
|
|
||||||
result := []maps.Map{}
|
|
||||||
for i := 60; i >= 1; i-- {
|
|
||||||
timestamp := time.Now().Unix() - int64(i)*60
|
|
||||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
|
||||||
total, ok := valuesMap[minute]
|
|
||||||
if ok {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": total / 60,
|
|
||||||
"text": numberutils.FormatBytes(total / 60),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": 0,
|
|
||||||
"text": numberutils.FormatBytes(0),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["values"] = result
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
|
||||||
|
|
||||||
package monitor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TrafficOutAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *TrafficOutAction) RunPost(params struct {
|
|
||||||
NodeId int64
|
|
||||||
}) {
|
|
||||||
resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
|
|
||||||
Role: "node",
|
|
||||||
NodeId: params.NodeId,
|
|
||||||
Item: nodeconfigs.NodeValueItemTrafficOut,
|
|
||||||
Range: nodeconfigs.NodeValueRangeMinute,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
valuesMap := map[string]int64{} // YmdHi => bytes
|
|
||||||
for _, v := range resp.NodeValues {
|
|
||||||
if len(v.ValueJSON) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
valueMap := maps.Map{}
|
|
||||||
err = json.Unmarshal(v.ValueJSON, &valueMap)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetInt64("total")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过去一个小时
|
|
||||||
result := []maps.Map{}
|
|
||||||
for i := 60; i >= 1; i-- {
|
|
||||||
timestamp := time.Now().Unix() - int64(i)*60
|
|
||||||
minute := timeutil.FormatTime("YmdHi", timestamp)
|
|
||||||
total, ok := valuesMap[minute]
|
|
||||||
if ok {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": total / 60,
|
|
||||||
"text": numberutils.FormatBytes(total / 60),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
result = append(result, maps.Map{
|
|
||||||
"label": timeutil.FormatTime("H:i", timestamp),
|
|
||||||
"value": 0,
|
|
||||||
"text": numberutils.FormatBytes(0),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["values"] = result
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package nodeutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitNodeInfo 初始化节点信息
|
||||||
|
func InitNodeInfo(action actionutils.ActionInterface, nodeId int64) error {
|
||||||
|
// 节点信息(用于菜单)
|
||||||
|
nodeResp, err := action.RPC().NodeRPC().FindEnabledNode(action.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: nodeId})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if nodeResp.Node == nil {
|
||||||
|
return errors.New("node '" + strconv.FormatInt(nodeId, 10) + "' not found")
|
||||||
|
}
|
||||||
|
var node = nodeResp.Node
|
||||||
|
action.ViewData()["node"] = maps.Map{
|
||||||
|
"id": node.Id,
|
||||||
|
"name": node.Name,
|
||||||
|
}
|
||||||
|
if node.NodeCluster != nil {
|
||||||
|
action.ViewData()["clusterId"] = node.NodeCluster.Id
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ package thresholds
|
|||||||
|
|
||||||
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/clusters/cluster/node/nodeutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
@@ -23,6 +24,13 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}) {
|
}) {
|
||||||
this.Data["nodeId"] = params.NodeId
|
this.Data["nodeId"] = params.NodeId
|
||||||
|
|
||||||
|
// 初始化节点信息(用于菜单)
|
||||||
|
err := nodeutils.InitNodeInfo(this, params.NodeId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 列出所有阈值
|
// 列出所有阈值
|
||||||
thresholdsResp, err := this.RPC().NodeThresholdRPC().FindAllEnabledNodeThresholds(this.AdminContext(), &pb.FindAllEnabledNodeThresholdsRequest{
|
thresholdsResp, err := this.RPC().NodeThresholdRPC().FindAllEnabledNodeThresholds(this.AdminContext(), &pb.FindAllEnabledNodeThresholdsRequest{
|
||||||
Role: "node",
|
Role: "node",
|
||||||
|
|||||||
249
internal/web/actions/default/clusters/cluster/nodes.go
Normal file
249
internal/web/actions/default/clusters/cluster/nodes.go
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
package cluster
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NodesAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *NodesAction) Init() {
|
||||||
|
this.Nav("", "node", "index")
|
||||||
|
this.SecondMenu("nodes")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *NodesAction) RunGet(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
GroupId int64
|
||||||
|
RegionId int64
|
||||||
|
InstalledState int
|
||||||
|
ActiveState int
|
||||||
|
Keyword string
|
||||||
|
|
||||||
|
CpuOrder string
|
||||||
|
MemoryOrder string
|
||||||
|
TrafficInOrder string
|
||||||
|
TrafficOutOrder string
|
||||||
|
}) {
|
||||||
|
this.Data["groupId"] = params.GroupId
|
||||||
|
this.Data["regionId"] = params.RegionId
|
||||||
|
this.Data["installState"] = params.InstalledState
|
||||||
|
this.Data["activeState"] = params.ActiveState
|
||||||
|
this.Data["keyword"] = params.Keyword
|
||||||
|
|
||||||
|
countAllResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["countAll"] = countAllResp.Count
|
||||||
|
|
||||||
|
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
NodeGroupId: params.GroupId,
|
||||||
|
NodeRegionId: params.RegionId,
|
||||||
|
InstallState: types.Int32(params.InstalledState),
|
||||||
|
ActiveState: types.Int32(params.ActiveState),
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
page := this.NewPage(countResp.Count)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
var req = &pb.ListEnabledNodesMatchRequest{
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
NodeGroupId: params.GroupId,
|
||||||
|
NodeRegionId: params.RegionId,
|
||||||
|
InstallState: types.Int32(params.InstalledState),
|
||||||
|
ActiveState: types.Int32(params.ActiveState),
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
}
|
||||||
|
if params.CpuOrder == "asc" {
|
||||||
|
req.CpuAsc = true
|
||||||
|
} else if params.CpuOrder == "desc" {
|
||||||
|
req.CpuDesc = true
|
||||||
|
} else if params.MemoryOrder == "asc" {
|
||||||
|
req.MemoryAsc = true
|
||||||
|
} else if params.MemoryOrder == "desc" {
|
||||||
|
req.MemoryDesc = true
|
||||||
|
} else if params.TrafficInOrder == "asc" {
|
||||||
|
req.TrafficInAsc = true
|
||||||
|
} else if params.TrafficInOrder == "desc" {
|
||||||
|
req.TrafficInDesc = true
|
||||||
|
} else if params.TrafficOutOrder == "asc" {
|
||||||
|
req.TrafficOutAsc = true
|
||||||
|
} else if params.TrafficOutOrder == "desc" {
|
||||||
|
req.TrafficOutDesc = true
|
||||||
|
}
|
||||||
|
nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), req)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nodeMaps := []maps.Map{}
|
||||||
|
for _, node := range nodesResp.Nodes {
|
||||||
|
// 状态
|
||||||
|
isSynced := false
|
||||||
|
status := &nodeconfigs.NodeStatus{}
|
||||||
|
if len(node.StatusJSON) > 0 {
|
||||||
|
err = json.Unmarshal(node.StatusJSON, &status)
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||||
|
isSynced = status.ConfigVersion == node.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
// IP
|
||||||
|
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
|
||||||
|
NodeId: node.Id,
|
||||||
|
Role: nodeconfigs.NodeRoleNode,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ipAddresses := []maps.Map{}
|
||||||
|
for _, addr := range ipAddressesResp.Addresses {
|
||||||
|
ipAddresses = append(ipAddresses, maps.Map{
|
||||||
|
"id": addr.Id,
|
||||||
|
"name": addr.Name,
|
||||||
|
"ip": addr.Ip,
|
||||||
|
"canAccess": addr.CanAccess,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分组
|
||||||
|
var groupMap maps.Map = nil
|
||||||
|
if node.NodeGroup != nil {
|
||||||
|
groupMap = maps.Map{
|
||||||
|
"id": node.NodeGroup.Id,
|
||||||
|
"name": node.NodeGroup.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 区域
|
||||||
|
var regionMap maps.Map = nil
|
||||||
|
if node.NodeRegion != nil {
|
||||||
|
regionMap = maps.Map{
|
||||||
|
"id": node.NodeRegion.Id,
|
||||||
|
"name": node.NodeRegion.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNS
|
||||||
|
dnsRouteNames := []string{}
|
||||||
|
for _, route := range node.DnsRoutes {
|
||||||
|
dnsRouteNames = append(dnsRouteNames, route.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeMaps = append(nodeMaps, maps.Map{
|
||||||
|
"id": node.Id,
|
||||||
|
"name": node.Name,
|
||||||
|
"isInstalled": node.IsInstalled,
|
||||||
|
"isOn": node.IsOn,
|
||||||
|
"isUp": node.IsUp,
|
||||||
|
"installStatus": maps.Map{
|
||||||
|
"isRunning": node.InstallStatus.IsRunning,
|
||||||
|
"isFinished": node.InstallStatus.IsFinished,
|
||||||
|
"isOk": node.InstallStatus.IsOk,
|
||||||
|
"error": node.InstallStatus.Error,
|
||||||
|
},
|
||||||
|
"status": maps.Map{
|
||||||
|
"isActive": status.IsActive,
|
||||||
|
"updatedAt": status.UpdatedAt,
|
||||||
|
"hostname": status.Hostname,
|
||||||
|
"cpuUsage": status.CPUUsage,
|
||||||
|
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
||||||
|
"memUsage": status.MemoryUsage,
|
||||||
|
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||||
|
"trafficInBytes": status.TrafficInBytes,
|
||||||
|
"trafficOutBytes": status.TrafficOutBytes,
|
||||||
|
},
|
||||||
|
"cluster": maps.Map{
|
||||||
|
"id": node.NodeCluster.Id,
|
||||||
|
"name": node.NodeCluster.Name,
|
||||||
|
},
|
||||||
|
"isSynced": isSynced,
|
||||||
|
"ipAddresses": ipAddresses,
|
||||||
|
"group": groupMap,
|
||||||
|
"region": regionMap,
|
||||||
|
"dnsRouteNames": dnsRouteNames,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["nodes"] = nodeMaps
|
||||||
|
|
||||||
|
// 所有分组
|
||||||
|
groupMaps := []maps.Map{}
|
||||||
|
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, group := range groupsResp.NodeGroups {
|
||||||
|
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{NodeGroupId: group.Id})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
countNodes := countResp.Count
|
||||||
|
groupName := group.Name
|
||||||
|
if countNodes > 0 {
|
||||||
|
groupName += "(" + strconv.FormatInt(countNodes, 10) + ")"
|
||||||
|
}
|
||||||
|
groupMaps = append(groupMaps, maps.Map{
|
||||||
|
"id": group.Id,
|
||||||
|
"name": groupName,
|
||||||
|
"countNodes": countNodes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["groups"] = groupMaps
|
||||||
|
|
||||||
|
// 所有区域
|
||||||
|
regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
regionMaps := []maps.Map{}
|
||||||
|
for _, region := range regionsResp.NodeRegions {
|
||||||
|
regionMaps = append(regionMaps, maps.Map{
|
||||||
|
"id": region.Id,
|
||||||
|
"name": region.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["regions"] = regionMaps
|
||||||
|
|
||||||
|
// 记录最近访问
|
||||||
|
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
||||||
|
ItemType: "cluster",
|
||||||
|
ItemId: params.ClusterId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -32,6 +32,9 @@ func (this *RunPopupAction) RunPost(params struct {
|
|||||||
this.Fail(err.Error())
|
this.Fail(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.Results == nil {
|
||||||
|
resp.Results = []*pb.ExecuteNodeClusterHealthCheckResponse_Result{}
|
||||||
|
}
|
||||||
this.Data["results"] = resp.Results
|
this.Data["results"] = resp.Results
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
firewallActions "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/firewall-actions"
|
firewallActions "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/firewall-actions"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/health"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/health"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/message"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/message"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/metrics"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/services"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/services"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/thresholds"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/thresholds"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/toa"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/toa"
|
||||||
@@ -67,6 +68,12 @@ func init() {
|
|||||||
GetPost("/updatePopup", new(thresholds.UpdatePopupAction)).
|
GetPost("/updatePopup", new(thresholds.UpdatePopupAction)).
|
||||||
Post("/delete", new(thresholds.DeleteAction)).
|
Post("/delete", new(thresholds.DeleteAction)).
|
||||||
|
|
||||||
|
// 指标
|
||||||
|
Prefix("/clusters/cluster/settings/metrics").
|
||||||
|
Get("", new(metrics.IndexAction)).
|
||||||
|
GetPost("/createPopup", new(metrics.CreatePopupAction)).
|
||||||
|
Post("/delete", new(metrics.DeleteAction)).
|
||||||
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreatePopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunGet(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
Category string
|
||||||
|
}) {
|
||||||
|
if len(params.Category) == 0 {
|
||||||
|
params.Category = "http"
|
||||||
|
}
|
||||||
|
this.Data["category"] = params.Category
|
||||||
|
this.Data["clusterId"] = params.ClusterId
|
||||||
|
|
||||||
|
countResp, err := this.RPC().MetricItemRPC().CountAllEnabledMetricItems(this.AdminContext(), &pb.CountAllEnabledMetricItemsRequest{Category: params.Category})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var count = countResp.Count
|
||||||
|
page := this.NewPage(count)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
itemsResp, err := this.RPC().MetricItemRPC().ListEnabledMetricItems(this.AdminContext(), &pb.ListEnabledMetricItemsRequest{
|
||||||
|
Category: params.Category,
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var itemMaps = []maps.Map{}
|
||||||
|
for _, item := range itemsResp.MetricItems {
|
||||||
|
// 是否已添加
|
||||||
|
existsResp, err := this.RPC().NodeClusterMetricItemRPC().ExistsNodeClusterMetricItem(this.AdminContext(), &pb.ExistsNodeClusterMetricItemRequest{
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
MetricItemId: item.Id,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var exists = existsResp.Exists
|
||||||
|
|
||||||
|
itemMaps = append(itemMaps, maps.Map{
|
||||||
|
"id": item.Id,
|
||||||
|
"name": item.Name,
|
||||||
|
"code": item.Code,
|
||||||
|
"isOn": item.IsOn,
|
||||||
|
"period": item.Period,
|
||||||
|
"periodUnit": item.PeriodUnit,
|
||||||
|
"periodUnitName": serverconfigs.FindMetricPeriodUnitName(item.PeriodUnit),
|
||||||
|
"keys": item.Keys,
|
||||||
|
"value": item.Value,
|
||||||
|
"valueName": serverconfigs.FindMetricValueName(item.Category, item.Value),
|
||||||
|
"category": item.Category,
|
||||||
|
"isPublic": item.IsPublic,
|
||||||
|
"isChecked": exists,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["items"] = itemMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunPost(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
ItemId int64
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("添加指标 %d 到集群 %d", params.ItemId, params.ClusterId)
|
||||||
|
|
||||||
|
_, err := this.RPC().NodeClusterMetricItemRPC().EnableNodeClusterMetricItem(this.AdminContext(), &pb.EnableNodeClusterMetricItemRequest{
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
MetricItemId: params.ItemId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package metrics
|
||||||
|
|
||||||
|
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 {
|
||||||
|
ClusterId int64
|
||||||
|
ItemId int64
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("从集群 %d 中移除指标 %d", params.ClusterId, params.ItemId)
|
||||||
|
|
||||||
|
_, err := this.RPC().NodeClusterMetricItemRPC().DisableNodeClusterMetricItem(this.AdminContext(), &pb.DisableNodeClusterMetricItemRequest{
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
MetricItemId: params.ItemId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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("", "setting", "setting")
|
||||||
|
this.SecondMenu("metric")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
Category string
|
||||||
|
}) {
|
||||||
|
if len(params.Category) == 0 {
|
||||||
|
params.Category = "http"
|
||||||
|
}
|
||||||
|
this.Data["category"] = params.Category
|
||||||
|
|
||||||
|
itemsResp, err := this.RPC().NodeClusterMetricItemRPC().FindAllNodeClusterMetricItems(this.AdminContext(), &pb.FindAllNodeClusterMetricItemsRequest{
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
Category: params.Category,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemMaps = []maps.Map{}
|
||||||
|
for _, item := range itemsResp.MetricItems {
|
||||||
|
itemMaps = append(itemMaps, maps.Map{
|
||||||
|
"id": item.Id,
|
||||||
|
"name": item.Name,
|
||||||
|
"code": item.Code,
|
||||||
|
"isOn": item.IsOn,
|
||||||
|
"period": item.Period,
|
||||||
|
"periodUnit": item.PeriodUnit,
|
||||||
|
"periodUnitName": serverconfigs.FindMetricPeriodUnitName(item.PeriodUnit),
|
||||||
|
"keys": item.Keys,
|
||||||
|
"value": item.Value,
|
||||||
|
"valueName": serverconfigs.FindMetricValueName(item.Category, item.Value),
|
||||||
|
"category": item.Category,
|
||||||
|
"isPublic": item.IsPublic,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["items"] = itemMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
package clusterutils
|
package clusterutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
@@ -38,7 +35,8 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
|||||||
action.Data["clusterId"] = clusterId
|
action.Data["clusterId"] = clusterId
|
||||||
|
|
||||||
if clusterId > 0 {
|
if clusterId > 0 {
|
||||||
cluster, err := dao.SharedNodeClusterDAO.FindEnabledNodeCluster(actionPtr.(rpc.ContextInterface).AdminContext(), clusterId)
|
var ctx = actionPtr.(actionutils.ActionInterface).AdminContext()
|
||||||
|
cluster, err := dao.SharedNodeClusterDAO.FindEnabledNodeCluster(ctx, clusterId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
logs.Error(err)
|
||||||
return
|
return
|
||||||
@@ -48,9 +46,22 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clusterInfo, err := dao.SharedNodeClusterDAO.FindEnabledNodeClusterConfigInfo(ctx, clusterId)
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if clusterInfo == nil {
|
||||||
|
action.WriteString("can not find cluster info")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
tabbar := actionutils.NewTabbar()
|
tabbar := actionutils.NewTabbar()
|
||||||
tabbar.Add("集群列表", "", "/clusters", "", false)
|
tabbar.Add("集群列表", "", "/clusters", "", false)
|
||||||
tabbar.Add("集群节点", "", "/clusters/cluster?clusterId="+clusterIdString, "server", selectedTabbar == "node")
|
if teaconst.IsPlus {
|
||||||
|
tabbar.Add("集群看板", "", "/clusters/cluster/boards?clusterId="+clusterIdString, "board", selectedTabbar == "board")
|
||||||
|
}
|
||||||
|
tabbar.Add("集群节点", "", "/clusters/cluster/nodes?clusterId="+clusterIdString, "server", selectedTabbar == "node")
|
||||||
tabbar.Add("集群设置", "", "/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting")
|
tabbar.Add("集群设置", "", "/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting")
|
||||||
tabbar.Add("删除集群", "", "/clusters/cluster/delete?clusterId="+clusterIdString, "trash", selectedTabbar == "delete")
|
tabbar.Add("删除集群", "", "/clusters/cluster/delete?clusterId="+clusterIdString, "trash", selectedTabbar == "delete")
|
||||||
|
|
||||||
@@ -64,7 +75,7 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
|||||||
secondMenuItem := action.Data.GetString("secondMenuItem")
|
secondMenuItem := action.Data.GetString("secondMenuItem")
|
||||||
switch selectedTabbar {
|
switch selectedTabbar {
|
||||||
case "setting":
|
case "setting":
|
||||||
action.Data["leftMenuItems"] = this.createSettingMenu(cluster, secondMenuItem)
|
action.Data["leftMenuItems"] = this.createSettingMenu(cluster, clusterInfo, secondMenuItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +83,7 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设置菜单
|
// 设置菜单
|
||||||
func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedItem string) (items []maps.Map) {
|
func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.FindEnabledNodeClusterConfigInfoResponse, selectedItem string) (items []maps.Map) {
|
||||||
clusterId := numberutils.FormatInt64(cluster.Id)
|
clusterId := numberutils.FormatInt64(cluster.Id)
|
||||||
items = append(items, maps.Map{
|
items = append(items, maps.Map{
|
||||||
"name": "基础设置",
|
"name": "基础设置",
|
||||||
@@ -92,25 +103,19 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt
|
|||||||
"isOn": cluster.HttpFirewallPolicyId > 0,
|
"isOn": cluster.HttpFirewallPolicyId > 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
{
|
items = append(items, maps.Map{
|
||||||
hasActions, _ := this.checkFirewallActions(cluster.Id)
|
"name": "WAF动作",
|
||||||
items = append(items, maps.Map{
|
"url": "/clusters/cluster/settings/firewall-actions?clusterId=" + clusterId,
|
||||||
"name": "WAF动作",
|
"isActive": selectedItem == "firewallAction",
|
||||||
"url": "/clusters/cluster/settings/firewall-actions?clusterId=" + clusterId,
|
"isOn": info != nil && info.HasFirewallActions,
|
||||||
"isActive": selectedItem == "firewallAction",
|
})
|
||||||
"isOn": hasActions,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
items = append(items, maps.Map{
|
||||||
healthCheckIsOn, _ := this.checkHealthCheckIsOn(cluster.Id)
|
"name": "健康检查",
|
||||||
items = append(items, maps.Map{
|
"url": "/clusters/cluster/settings/health?clusterId=" + clusterId,
|
||||||
"name": "健康检查",
|
"isActive": selectedItem == "health",
|
||||||
"url": "/clusters/cluster/settings/health?clusterId=" + clusterId,
|
"isOn": info != nil && info.HealthCheckIsOn,
|
||||||
"isActive": selectedItem == "health",
|
})
|
||||||
"isOn": healthCheckIsOn,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
items = append(items, maps.Map{
|
items = append(items, maps.Map{
|
||||||
"name": "DNS设置",
|
"name": "DNS设置",
|
||||||
@@ -118,22 +123,26 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt
|
|||||||
"isActive": selectedItem == "dns",
|
"isActive": selectedItem == "dns",
|
||||||
"isOn": cluster.DnsDomainId > 0 || len(cluster.DnsName) > 0,
|
"isOn": cluster.DnsDomainId > 0 || len(cluster.DnsName) > 0,
|
||||||
})
|
})
|
||||||
|
items = append(items, maps.Map{
|
||||||
|
"name": "统计指标",
|
||||||
|
"url": "/clusters/cluster/settings/metrics?clusterId=" + clusterId,
|
||||||
|
"isActive": selectedItem == "metric",
|
||||||
|
"isOn": info != nil && info.HasMetricItems,
|
||||||
|
})
|
||||||
|
|
||||||
if teaconst.IsPlus {
|
if teaconst.IsPlus {
|
||||||
hasThresholds, _ := this.checkThresholds(cluster.Id)
|
|
||||||
items = append(items, maps.Map{
|
items = append(items, maps.Map{
|
||||||
"name": "阈值设置",
|
"name": "阈值设置",
|
||||||
"url": "/clusters/cluster/settings/thresholds?clusterId=" + clusterId,
|
"url": "/clusters/cluster/settings/thresholds?clusterId=" + clusterId,
|
||||||
"isActive": selectedItem == "threshold",
|
"isActive": selectedItem == "threshold",
|
||||||
"isOn": hasThresholds,
|
"isOn": info != nil && info.HasThresholds,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
if teaconst.IsPlus {
|
|
||||||
hasMessageReceivers, _ := this.checkMessages(cluster.Id)
|
|
||||||
items = append(items, maps.Map{
|
items = append(items, maps.Map{
|
||||||
"name": "消息通知",
|
"name": "消息通知",
|
||||||
"url": "/clusters/cluster/settings/message?clusterId=" + clusterId,
|
"url": "/clusters/cluster/settings/message?clusterId=" + clusterId,
|
||||||
"isActive": selectedItem == "message",
|
"isActive": selectedItem == "message",
|
||||||
"isOn": hasMessageReceivers,
|
"isOn": info != nil && info.HasMessageReceivers,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,75 +157,13 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt
|
|||||||
"url": "/clusters/cluster/settings/services?clusterId=" + clusterId,
|
"url": "/clusters/cluster/settings/services?clusterId=" + clusterId,
|
||||||
"isActive": selectedItem == "service",
|
"isActive": selectedItem == "service",
|
||||||
})
|
})
|
||||||
items = append(items, maps.Map{
|
{
|
||||||
"name": "TOA设置",
|
items = append(items, maps.Map{
|
||||||
"url": "/clusters/cluster/settings/toa?clusterId=" + clusterId,
|
"name": "TOA设置",
|
||||||
"isActive": selectedItem == "toa",
|
"url": "/clusters/cluster/settings/toa?clusterId=" + clusterId,
|
||||||
})
|
"isActive": selectedItem == "toa",
|
||||||
|
"isOn": info != nil && info.IsTOAEnabled,
|
||||||
|
})
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查健康检查是否开启
|
|
||||||
func (this *ClusterHelper) checkHealthCheckIsOn(clusterId int64) (bool, error) {
|
|
||||||
rpcClient, err := rpc.SharedRPC()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
resp, err := rpcClient.NodeClusterRPC().FindNodeClusterHealthCheckConfig(rpcClient.Context(0), &pb.FindNodeClusterHealthCheckConfigRequest{NodeClusterId: clusterId})
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if len(resp.HealthCheckJSON) > 0 {
|
|
||||||
healthCheckConfig := &serverconfigs.HealthCheckConfig{}
|
|
||||||
err = json.Unmarshal(resp.HealthCheckJSON, healthCheckConfig)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return healthCheckConfig.IsOn, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否有WAF动作
|
|
||||||
func (this *ClusterHelper) checkFirewallActions(clusterId int64) (bool, error) {
|
|
||||||
rpcClient, err := rpc.SharedRPC()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
resp, err := rpcClient.NodeClusterFirewallActionRPC().CountAllEnabledNodeClusterFirewallActions(rpcClient.Context(0), &pb.CountAllEnabledNodeClusterFirewallActionsRequest{NodeClusterId: clusterId})
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return resp.Count > 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查阈值是否已经设置
|
|
||||||
func (this *ClusterHelper) checkThresholds(clusterId int64) (bool, error) {
|
|
||||||
rpcClient, err := rpc.SharedRPC()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
resp, err := rpcClient.NodeThresholdRPC().CountAllEnabledNodeThresholds(rpcClient.Context(0), &pb.CountAllEnabledNodeThresholdsRequest{
|
|
||||||
Role: "node",
|
|
||||||
NodeClusterId: clusterId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return resp.Count > 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查消息通知是否已经设置
|
|
||||||
func (this *ClusterHelper) checkMessages(clusterId int64) (bool, error) {
|
|
||||||
rpcClient, err := rpc.SharedRPC()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
resp, err := rpcClient.MessageReceiverRPC().CountAllEnabledMessageReceivers(rpcClient.Context(0), &pb.CountAllEnabledMessageReceiversRequest{
|
|
||||||
NodeClusterId: clusterId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return resp.Count > 0, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ func (this *CreateAction) 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私钥")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,9 @@ func (this *UpdateAction) 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私钥")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,12 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 服务数
|
||||||
|
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithNodeClusterId(this.AdminContext(), &pb.CountAllEnabledServersWithNodeClusterIdRequest{NodeClusterId: cluster.Id})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
}
|
||||||
|
|
||||||
clusterMaps = append(clusterMaps, maps.Map{
|
clusterMaps = append(clusterMaps, maps.Map{
|
||||||
"id": cluster.Id,
|
"id": cluster.Id,
|
||||||
"name": cluster.Name,
|
"name": cluster.Name,
|
||||||
@@ -125,6 +131,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
"dnsDomainId": cluster.DnsDomainId,
|
"dnsDomainId": cluster.DnsDomainId,
|
||||||
"dnsName": cluster.DnsName,
|
"dnsName": cluster.DnsName,
|
||||||
"dnsDomainName": dnsDomainName,
|
"dnsDomainName": dnsDomainName,
|
||||||
|
"countServers": countServersResp.Count,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
133
internal/web/actions/default/dashboard/boards/dns.go
Normal file
133
internal/web/actions/default/dashboard/boards/dns.go
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package boards
|
||||||
|
|
||||||
|
import (
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DnsAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DnsAction) Init() {
|
||||||
|
this.Nav("", "", "dns")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DnsAction) RunGet(params struct{}) {
|
||||||
|
if !teaconst.IsPlus {
|
||||||
|
this.RedirectURL("/dashboard")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := this.RPC().NSRPC().ComposeNSBoard(this.AdminContext(), &pb.ComposeNSBoardRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["board"] = maps.Map{
|
||||||
|
"countDomains": resp.CountNSDomains,
|
||||||
|
"countRecords": resp.CountNSRecords,
|
||||||
|
"countClusters": resp.CountNSClusters,
|
||||||
|
"countNodes": resp.CountNSNodes,
|
||||||
|
"countOfflineNodes": resp.CountOfflineNSNodes,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 流量排行
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.HourlyTrafficStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
|
||||||
|
"hour": stat.Hour[8:],
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["hourlyStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.DailyTrafficStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["dailyStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 域名排行
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.TopNSDomainStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"domainId": stat.NsDomainId,
|
||||||
|
"domainName": stat.NsDomainName,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["topDomainStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点排行
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.TopNSNodeStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"clusterId": stat.NsClusterId,
|
||||||
|
"nodeId": stat.NsNodeId,
|
||||||
|
"nodeName": stat.NsNodeName,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["topNodeStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPU
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.CpuNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["cpuValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.MemoryNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["memoryValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.LoadNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["loadValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
249
internal/web/actions/default/dashboard/boards/index.go
Normal file
249
internal/web/actions/default/dashboard/boards/index.go
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package boards
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
|
"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"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "index")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct{}) {
|
||||||
|
if !teaconst.IsPlus {
|
||||||
|
this.RedirectURL("/dashboard")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取得用户的权限
|
||||||
|
module, ok := configloaders.FindFirstAdminModule(this.AdminId())
|
||||||
|
if ok {
|
||||||
|
if module != "dashboard" {
|
||||||
|
for _, m := range configloaders.AllModuleMaps() {
|
||||||
|
if m.GetString("code") == module {
|
||||||
|
this.RedirectURL(m.GetString("url"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取看板数据
|
||||||
|
resp, err := this.RPC().AdminRPC().ComposeAdminDashboard(this.AdminContext(), &pb.ComposeAdminDashboardRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["dashboard"] = maps.Map{
|
||||||
|
"countServers": resp.CountServers,
|
||||||
|
"countNodeClusters": resp.CountNodeClusters,
|
||||||
|
"countNodes": resp.CountNodes,
|
||||||
|
"countUsers": resp.CountUsers,
|
||||||
|
"countAPINodes": resp.CountAPINodes,
|
||||||
|
"countDBNodes": resp.CountDBNodes,
|
||||||
|
"countUserNodes": resp.CountUserNodes,
|
||||||
|
|
||||||
|
"canGoServers": configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeServer),
|
||||||
|
"canGoNodes": configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeNode),
|
||||||
|
"canGoSettings": configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeSetting),
|
||||||
|
"canGoUsers": configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeUser),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 今日流量
|
||||||
|
todayTrafficBytes := int64(0)
|
||||||
|
if len(resp.DailyTrafficStats) > 0 {
|
||||||
|
todayTrafficBytes = resp.DailyTrafficStats[len(resp.DailyTrafficStats)-1].Bytes
|
||||||
|
}
|
||||||
|
todayTrafficString := numberutils.FormatBytes(todayTrafficBytes)
|
||||||
|
result := regexp.MustCompile(`^(?U)(.+)([a-zA-Z]+)$`).FindStringSubmatch(todayTrafficString)
|
||||||
|
if len(result) > 2 {
|
||||||
|
this.Data["todayTraffic"] = result[1]
|
||||||
|
this.Data["todayTrafficUnit"] = result[2]
|
||||||
|
} else {
|
||||||
|
this.Data["todayTraffic"] = todayTrafficString
|
||||||
|
this.Data["todayTrafficUnit"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 24小时流量趋势
|
||||||
|
{
|
||||||
|
statMaps := []maps.Map{}
|
||||||
|
for _, stat := range resp.HourlyTrafficStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
"cachedBytes": stat.CachedBytes,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"countCachedRequests": stat.CountCachedRequests,
|
||||||
|
"countAttackRequests": stat.CountAttackRequests,
|
||||||
|
"attackBytes": stat.AttackBytes,
|
||||||
|
"day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
|
||||||
|
"hour": stat.Hour[8:],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["hourlyTrafficStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 15天流量趋势
|
||||||
|
{
|
||||||
|
statMaps := []maps.Map{}
|
||||||
|
for _, stat := range resp.DailyTrafficStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
"cachedBytes": stat.CachedBytes,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"countCachedRequests": stat.CountCachedRequests,
|
||||||
|
"countAttackRequests": stat.CountAttackRequests,
|
||||||
|
"attackBytes": stat.AttackBytes,
|
||||||
|
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["dailyTrafficStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点排行
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.TopNodeStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"nodeId": stat.NodeId,
|
||||||
|
"nodeName": stat.NodeName,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["topNodeStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 域名排行
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.TopDomainStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"serverId": stat.ServerId,
|
||||||
|
"domain": stat.Domain,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["topDomainStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 版本升级
|
||||||
|
if resp.NodeUpgradeInfo != nil {
|
||||||
|
this.Data["nodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": resp.NodeUpgradeInfo.CountNodes,
|
||||||
|
"version": resp.NodeUpgradeInfo.NewVersion,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.Data["nodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": 0,
|
||||||
|
"version": "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp.MonitorNodeUpgradeInfo != nil {
|
||||||
|
this.Data["monitorNodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": resp.MonitorNodeUpgradeInfo.CountNodes,
|
||||||
|
"version": resp.MonitorNodeUpgradeInfo.NewVersion,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.Data["monitorNodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": 0,
|
||||||
|
"version": "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp.ApiNodeUpgradeInfo != nil {
|
||||||
|
this.Data["apiNodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": resp.ApiNodeUpgradeInfo.CountNodes,
|
||||||
|
"version": resp.ApiNodeUpgradeInfo.NewVersion,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.Data["apiNodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": 0,
|
||||||
|
"version": "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp.UserNodeUpgradeInfo != nil {
|
||||||
|
this.Data["userNodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": resp.UserNodeUpgradeInfo.CountNodes,
|
||||||
|
"version": resp.UserNodeUpgradeInfo.NewVersion,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.Data["userNodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": 0,
|
||||||
|
"version": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp.AuthorityNodeUpgradeInfo != nil {
|
||||||
|
this.Data["authorityNodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": resp.AuthorityNodeUpgradeInfo.CountNodes,
|
||||||
|
"version": resp.AuthorityNodeUpgradeInfo.NewVersion,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.Data["authorityNodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": 0,
|
||||||
|
"version": "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp.NsNodeUpgradeInfo != nil {
|
||||||
|
this.Data["nsNodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": resp.NsNodeUpgradeInfo.CountNodes,
|
||||||
|
"version": resp.NsNodeUpgradeInfo.NewVersion,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.Data["nsNodeUpgradeInfo"] = maps.Map{
|
||||||
|
"count": 0,
|
||||||
|
"version": "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指标
|
||||||
|
{
|
||||||
|
var chartMaps = []maps.Map{}
|
||||||
|
for _, chart := range resp.MetricDataCharts {
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range chart.MetricStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"keys": stat.Keys,
|
||||||
|
"time": stat.Time,
|
||||||
|
"value": stat.Value,
|
||||||
|
"count": stat.SumCount,
|
||||||
|
"total": stat.SumTotal,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
chartMaps = append(chartMaps, maps.Map{
|
||||||
|
"chart": maps.Map{
|
||||||
|
"id": chart.MetricChart.Id,
|
||||||
|
"name": chart.MetricChart.Name,
|
||||||
|
"widthDiv": chart.MetricChart.WidthDiv,
|
||||||
|
"isOn": chart.MetricChart.IsOn,
|
||||||
|
"maxItems": chart.MetricChart.MaxItems,
|
||||||
|
"type": chart.MetricChart.Type,
|
||||||
|
},
|
||||||
|
"item": maps.Map{
|
||||||
|
"id": chart.MetricChart.MetricItem.Id,
|
||||||
|
"name": chart.MetricChart.MetricItem.Name,
|
||||||
|
"period": chart.MetricChart.MetricItem.Period,
|
||||||
|
"periodUnit": chart.MetricChart.MetricItem.PeriodUnit,
|
||||||
|
"valueType": serverconfigs.FindMetricValueType(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||||
|
"valueTypeName": serverconfigs.FindMetricValueName(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||||
|
"keys": chart.MetricChart.MetricItem.Keys,
|
||||||
|
},
|
||||||
|
"stats": statMaps,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["metricCharts"] = chartMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
103
internal/web/actions/default/dashboard/boards/user.go
Normal file
103
internal/web/actions/default/dashboard/boards/user.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package boards
|
||||||
|
|
||||||
|
import (
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UserAction) Init() {
|
||||||
|
this.Nav("", "", "user")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UserAction) RunGet(params struct{}) {
|
||||||
|
if !teaconst.IsPlus {
|
||||||
|
this.RedirectURL("/dashboard")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := this.RPC().UserRPC().ComposeUserGlobalBoard(this.AdminContext(), &pb.ComposeUserGlobalBoardRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["board"] = maps.Map{
|
||||||
|
"totalUsers": resp.TotalUsers,
|
||||||
|
"countTodayUsers": resp.CountTodayUsers,
|
||||||
|
"countWeeklyUsers": resp.CountWeeklyUsers,
|
||||||
|
"countUserNodes": resp.CountUserNodes,
|
||||||
|
"countOfflineUserNodes": resp.CountOfflineUserNodes,
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
statMaps := []maps.Map{}
|
||||||
|
for _, stat := range resp.DailyStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"day": stat.Day,
|
||||||
|
"count": stat.Count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["dailyStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPU
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.CpuNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["cpuValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.MemoryNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["memoryValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.LoadNodeValues {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||||
|
"value": types.Float32(string(stat.ValueJSON)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["loadValues"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 流量排行
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.TopTrafficStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"userId": stat.UserId,
|
||||||
|
"userName": stat.UserName,
|
||||||
|
"countRequests": stat.CountRequests,
|
||||||
|
"bytes": stat.Bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["topTrafficStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
76
internal/web/actions/default/dashboard/boards/waf.go
Normal file
76
internal/web/actions/default/dashboard/boards/waf.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package boards
|
||||||
|
|
||||||
|
import (
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WafAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *WafAction) Init() {
|
||||||
|
this.Nav("", "", "waf")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *WafAction) RunGet(params struct{}) {
|
||||||
|
if !teaconst.IsPlus {
|
||||||
|
this.RedirectURL("/dashboard")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := this.RPC().FirewallRPC().ComposeFirewallGlobalBoard(this.AdminContext(), &pb.ComposeFirewallGlobalBoardRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["board"] = maps.Map{
|
||||||
|
"countDailyLogs": resp.CountDailyLogs,
|
||||||
|
"countDailyBlocks": resp.CountDailyBlocks,
|
||||||
|
"countDailyCaptcha": resp.CountDailyCaptcha,
|
||||||
|
"countWeeklyBlocks": resp.CountWeeklyBlocks,
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.HourlyStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"hour": stat.Hour,
|
||||||
|
"countLogs": stat.CountLogs,
|
||||||
|
"countCaptcha": stat.CountCaptcha,
|
||||||
|
"countBlocks": stat.CountBlocks,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["hourlyStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.DailyStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"day": stat.Day,
|
||||||
|
"countLogs": stat.CountLogs,
|
||||||
|
"countCaptcha": stat.CountCaptcha,
|
||||||
|
"countBlocks": stat.CountBlocks,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["dailyStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range resp.HttpFirewallRuleGroups {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"name": stat.HttpFirewallRuleGroup.Name,
|
||||||
|
"count": stat.Count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["groupStats"] = statMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
28
internal/web/actions/default/dashboard/boards/wafLogs.go
Normal file
28
internal/web/actions/default/dashboard/boards/wafLogs.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package boards
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WafLogsAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *WafLogsAction) RunPost(params struct{}) {
|
||||||
|
resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||||
|
HasFirewallPolicy: true,
|
||||||
|
Reverse: false,
|
||||||
|
Day: timeutil.Format("Ymd"),
|
||||||
|
Size: 5,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["accessLogs"] = resp.HttpAccessLogs
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
package dashboard
|
package dashboard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"math"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,6 +22,11 @@ func (this *IndexAction) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct{}) {
|
func (this *IndexAction) RunGet(params struct{}) {
|
||||||
|
if teaconst.IsPlus {
|
||||||
|
this.RedirectURL("/dashboard/boards")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 取得用户的权限
|
// 取得用户的权限
|
||||||
module, ok := configloaders.FindFirstAdminModule(this.AdminId())
|
module, ok := configloaders.FindFirstAdminModule(this.AdminId())
|
||||||
if ok {
|
if ok {
|
||||||
@@ -58,7 +66,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
if len(resp.DailyTrafficStats) > 0 {
|
if len(resp.DailyTrafficStats) > 0 {
|
||||||
todayTrafficBytes = resp.DailyTrafficStats[len(resp.DailyTrafficStats)-1].Bytes
|
todayTrafficBytes = resp.DailyTrafficStats[len(resp.DailyTrafficStats)-1].Bytes
|
||||||
}
|
}
|
||||||
todayTrafficString := numberutils.FormatBits(todayTrafficBytes * 8)
|
todayTrafficString := numberutils.FormatBytes(todayTrafficBytes)
|
||||||
result := regexp.MustCompile(`^(?U)(.+)([a-zA-Z]+)$`).FindStringSubmatch(todayTrafficString)
|
result := regexp.MustCompile(`^(?U)(.+)([a-zA-Z]+)$`).FindStringSubmatch(todayTrafficString)
|
||||||
if len(result) > 2 {
|
if len(result) > 2 {
|
||||||
this.Data["todayTraffic"] = result[1]
|
this.Data["todayTraffic"] = result[1]
|
||||||
@@ -73,7 +81,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
statMaps := []maps.Map{}
|
statMaps := []maps.Map{}
|
||||||
for _, stat := range resp.HourlyTrafficStats {
|
for _, stat := range resp.HourlyTrafficStats {
|
||||||
statMaps = append(statMaps, maps.Map{
|
statMaps = append(statMaps, maps.Map{
|
||||||
"count": math.Ceil((float64(stat.Bytes)*8/1000/1000/1000)*1000) / 1000,
|
"bytes": stat.Bytes,
|
||||||
"hour": stat.Hour[8:],
|
"hour": stat.Hour[8:],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -85,7 +93,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
statMaps := []maps.Map{}
|
statMaps := []maps.Map{}
|
||||||
for _, stat := range resp.DailyTrafficStats {
|
for _, stat := range resp.DailyTrafficStats {
|
||||||
statMaps = append(statMaps, maps.Map{
|
statMaps = append(statMaps, maps.Map{
|
||||||
"count": math.Ceil((float64(stat.Bytes)*8/1000/1000/1000)*1000) / 1000,
|
"bytes": stat.Bytes,
|
||||||
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -160,5 +168,43 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 指标
|
||||||
|
{
|
||||||
|
var chartMaps = []maps.Map{}
|
||||||
|
for _, chart := range resp.MetricDataCharts {
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range chart.MetricStats {
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"keys": stat.Keys,
|
||||||
|
"time": stat.Time,
|
||||||
|
"value": stat.Value,
|
||||||
|
"count": stat.SumCount,
|
||||||
|
"total": stat.SumTotal,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
chartMaps = append(chartMaps, maps.Map{
|
||||||
|
"chart": maps.Map{
|
||||||
|
"id": chart.MetricChart.Id,
|
||||||
|
"name": chart.MetricChart.Name,
|
||||||
|
"widthDiv": chart.MetricChart.WidthDiv,
|
||||||
|
"isOn": chart.MetricChart.IsOn,
|
||||||
|
"maxItems": chart.MetricChart.MaxItems,
|
||||||
|
"type": chart.MetricChart.Type,
|
||||||
|
},
|
||||||
|
"item": maps.Map{
|
||||||
|
"id": chart.MetricChart.MetricItem.Id,
|
||||||
|
"name": chart.MetricChart.MetricItem.Name,
|
||||||
|
"period": chart.MetricChart.MetricItem.Period,
|
||||||
|
"periodUnit": chart.MetricChart.MetricItem.PeriodUnit,
|
||||||
|
"valueType": serverconfigs.FindMetricValueType(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||||
|
"valueTypeName": serverconfigs.FindMetricValueName(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||||
|
"keys": chart.MetricChart.MetricItem.Keys,
|
||||||
|
},
|
||||||
|
"stats": statMaps,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["metricCharts"] = chartMaps
|
||||||
|
}
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package dashboard
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dashboard/boards"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/iwind/TeaGo"
|
"github.com/iwind/TeaGo"
|
||||||
)
|
)
|
||||||
@@ -12,6 +13,15 @@ func init() {
|
|||||||
Data("teaMenu", "dashboard").
|
Data("teaMenu", "dashboard").
|
||||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
|
||||||
GetPost("", new(IndexAction)).
|
GetPost("", new(IndexAction)).
|
||||||
|
|
||||||
|
// 看板
|
||||||
|
Prefix("/dashboard/boards").
|
||||||
|
Get("", new(boards.IndexAction)).
|
||||||
|
Get("/waf", new(boards.WafAction)).
|
||||||
|
Post("/wafLogs", new(boards.WafLogsAction)).
|
||||||
|
Get("/dns", new(boards.DnsAction)).
|
||||||
|
Get("/user", new(boards.UserAction)).
|
||||||
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提交
|
// RunPost 提交
|
||||||
func (this *IndexAction) RunPost(params struct {
|
func (this *IndexAction) RunPost(params struct {
|
||||||
Token string
|
Token string
|
||||||
Username string
|
Username string
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
|||||||
logs.Error(err)
|
logs.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clusterResp, err := rpcClient.NSClusterRPC().FindEnabledNSCluster(actionPtr.(rpc.ContextInterface).AdminContext(), &pb.FindEnabledNSClusterRequest{
|
clusterResp, err := rpcClient.NSClusterRPC().FindEnabledNSCluster(actionPtr.(actionutils.ActionInterface).AdminContext(), &pb.FindEnabledNSClusterRequest{
|
||||||
NsClusterId: clusterId,
|
NsClusterId: clusterId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
"ttl": record.Ttl,
|
"ttl": record.Ttl,
|
||||||
"weight": record.Weight,
|
"weight": record.Weight,
|
||||||
"description": record.Description,
|
"description": record.Description,
|
||||||
|
"isOn": record.IsOn,
|
||||||
"routes": routeMaps,
|
"routes": routeMaps,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
|
|||||||
"ttl": record.Ttl,
|
"ttl": record.Ttl,
|
||||||
"weight": record.Weight,
|
"weight": record.Weight,
|
||||||
"description": record.Description,
|
"description": record.Description,
|
||||||
|
"isOn": record.IsOn,
|
||||||
"routeIds": routeIds,
|
"routeIds": routeIds,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +82,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
Value string
|
Value string
|
||||||
Ttl int32
|
Ttl int32
|
||||||
Description string
|
Description string
|
||||||
|
IsOn bool
|
||||||
RouteIds []int64
|
RouteIds []int64
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
@@ -106,6 +108,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
Type: params.Type,
|
Type: params.Type,
|
||||||
Value: params.Value,
|
Value: params.Value,
|
||||||
Ttl: params.Ttl,
|
Ttl: params.Ttl,
|
||||||
|
IsOn: params.IsOn,
|
||||||
NsRouteIds: params.RouteIds,
|
NsRouteIds: params.RouteIds,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package ns
|
package ns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
@@ -19,6 +20,11 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
UserId int64
|
UserId int64
|
||||||
Keyword string
|
Keyword string
|
||||||
}) {
|
}) {
|
||||||
|
if !teaconst.IsPlus {
|
||||||
|
this.RedirectURL("/")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["clusterId"] = params.ClusterId
|
this.Data["clusterId"] = params.ClusterId
|
||||||
this.Data["userId"] = params.UserId
|
this.Data["userId"] = params.UserId
|
||||||
this.Data["keyword"] = params.Keyword
|
this.Data["keyword"] = params.Keyword
|
||||||
|
|||||||
17
internal/web/actions/default/recover/helper.go
Normal file
17
internal/web/actions/default/recover/helper.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package recover
|
||||||
|
|
||||||
|
import (
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Helper struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
|
||||||
|
if !teaconst.IsRecoverMode {
|
||||||
|
actionPtr.Object().RedirectURL("/")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
package board
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package recover
|
||||||
|
|
||||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
|
||||||
@@ -7,8 +9,7 @@ type IndexAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) Init() {
|
func (this *IndexAction) Init() {
|
||||||
this.Nav("", "board", "")
|
this.Nav("", "", "")
|
||||||
this.SecondMenu("index")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct{}) {
|
func (this *IndexAction) RunGet(params struct{}) {
|
||||||
15
internal/web/actions/default/recover/init.go
Normal file
15
internal/web/actions/default/recover/init.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package recover
|
||||||
|
|
||||||
|
import "github.com/iwind/TeaGo"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
|
server.
|
||||||
|
Helper(new(Helper)).
|
||||||
|
Prefix("/recover").
|
||||||
|
Get("", new(IndexAction)).
|
||||||
|
Post("/validateApi", new(ValidateApiAction)).
|
||||||
|
Post("/updateHosts", new(UpdateHostsAction)).
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
192
internal/web/actions/default/recover/updateHosts.go
Normal file
192
internal/web/actions/default/recover/updateHosts.go
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package recover
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateHostsAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateHostsAction) RunPost(params struct {
|
||||||
|
Protocol string
|
||||||
|
Host string
|
||||||
|
Port string
|
||||||
|
NodeId string
|
||||||
|
NodeSecret string
|
||||||
|
|
||||||
|
OldHosts []string
|
||||||
|
NewHosts []string
|
||||||
|
}) {
|
||||||
|
if len(params.OldHosts) != len(params.NewHosts) {
|
||||||
|
this.Fail("参数配置错误,请刷新页面后重试")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := rpc.NewRPCClient(&configs.APIConfig{
|
||||||
|
RPC: struct {
|
||||||
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
}{
|
||||||
|
Endpoints: []string{params.Protocol + "://" + configutils.QuoteIP(params.Host) + ":" + params.Port},
|
||||||
|
},
|
||||||
|
NodeId: params.NodeId,
|
||||||
|
Secret: params.NodeSecret,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("host", "测试API节点时出错,请检查配置,错误信息:"+err.Error())
|
||||||
|
}
|
||||||
|
_, err = client.APINodeRPC().FindCurrentAPINodeVersion(client.APIContext(0), &pb.FindCurrentAPINodeVersionRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("host", "无法连接此API节点,错误信息:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取管理员节点信息
|
||||||
|
apiTokensResp, err := client.APITokenRPC().FindAllEnabledAPITokens(client.APIContext(0), &pb.FindAllEnabledAPITokensRequest{Role: "admin"})
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("读取管理员令牌失败:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiTokens = apiTokensResp.ApiTokens
|
||||||
|
if len(apiTokens) == 0 {
|
||||||
|
this.Fail("数据库中没有管理员令牌信息,请确认数据是否完整")
|
||||||
|
}
|
||||||
|
var adminAPIToken = apiTokens[0]
|
||||||
|
|
||||||
|
// API节点列表
|
||||||
|
nodesResp, err := client.APINodeRPC().FindAllEnabledAPINodes(client.Context(0), &pb.FindAllEnabledAPINodesRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("获取API节点列表失败,错误信息:" + err.Error())
|
||||||
|
}
|
||||||
|
var endpoints = []string{}
|
||||||
|
for _, node := range nodesResp.Nodes {
|
||||||
|
if !node.IsOn {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// http
|
||||||
|
if len(node.HttpJSON) > 0 {
|
||||||
|
for index, oldHost := range params.OldHosts {
|
||||||
|
if len(params.NewHosts[index]) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node.HttpJSON = bytes.ReplaceAll(node.HttpJSON, []byte("\""+oldHost+"\""), []byte("\""+params.NewHosts[index]+"\""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https
|
||||||
|
if len(node.HttpsJSON) > 0 {
|
||||||
|
for index, oldHost := range params.OldHosts {
|
||||||
|
if len(params.NewHosts[index]) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node.HttpsJSON = bytes.ReplaceAll(node.HttpsJSON, []byte("\""+oldHost+"\""), []byte("\""+params.NewHosts[index]+"\""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restHTTP
|
||||||
|
if len(node.RestHTTPJSON) > 0 {
|
||||||
|
for index, oldHost := range params.OldHosts {
|
||||||
|
if len(params.NewHosts[index]) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node.RestHTTPJSON = bytes.ReplaceAll(node.RestHTTPJSON, []byte("\""+oldHost+"\""), []byte("\""+params.NewHosts[index]+"\""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restHTTPS
|
||||||
|
if len(node.RestHTTPSJSON) > 0 {
|
||||||
|
for index, oldHost := range params.OldHosts {
|
||||||
|
if len(params.NewHosts[index]) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node.RestHTTPSJSON = bytes.ReplaceAll(node.RestHTTPSJSON, []byte("\""+oldHost+"\""), []byte("\""+params.NewHosts[index]+"\""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// access addrs
|
||||||
|
if len(node.AccessAddrsJSON) > 0 {
|
||||||
|
for index, oldHost := range params.OldHosts {
|
||||||
|
if len(params.NewHosts[index]) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node.AccessAddrsJSON = bytes.ReplaceAll(node.AccessAddrsJSON, []byte("\""+oldHost+"\""), []byte("\""+params.NewHosts[index]+"\""))
|
||||||
|
}
|
||||||
|
|
||||||
|
var addrs []*serverconfigs.NetworkAddressConfig
|
||||||
|
err = json.Unmarshal(node.AccessAddrsJSON, &addrs)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("读取节点访问地址失败:" + err.Error())
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
err = addr.Init()
|
||||||
|
if err != nil {
|
||||||
|
// 暂时不提示错误
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, a := range addr.FullAddresses() {
|
||||||
|
if !lists.ContainsString(endpoints, a) {
|
||||||
|
endpoints = append(endpoints, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存
|
||||||
|
_, err = client.APINodeRPC().UpdateAPINode(client.Context(0), &pb.UpdateAPINodeRequest{
|
||||||
|
NodeId: node.Id,
|
||||||
|
Name: node.Name,
|
||||||
|
Description: node.Description,
|
||||||
|
HttpJSON: node.HttpJSON,
|
||||||
|
HttpsJSON: node.HttpsJSON,
|
||||||
|
AccessAddrsJSON: node.AccessAddrsJSON,
|
||||||
|
IsOn: node.IsOn,
|
||||||
|
RestIsOn: node.RestIsOn,
|
||||||
|
RestHTTPJSON: node.RestHTTPJSON,
|
||||||
|
RestHTTPSJSON: node.RestHTTPSJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("保存API节点信息失败:" + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改api.yaml
|
||||||
|
var apiConfig = &configs.APIConfig{
|
||||||
|
RPC: struct {
|
||||||
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
}{
|
||||||
|
Endpoints: endpoints,
|
||||||
|
},
|
||||||
|
NodeId: adminAPIToken.NodeId,
|
||||||
|
Secret: adminAPIToken.Secret,
|
||||||
|
}
|
||||||
|
err = apiConfig.WriteFile(Tea.Root + "/configs/api.yaml")
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("保存configs/api.yaml失败:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载api.yaml
|
||||||
|
rpcClient, err := rpc.SharedRPC()
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("初始化RPC失败:" + err.Error())
|
||||||
|
}
|
||||||
|
err = rpcClient.UpdateConfig(apiConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("修改API配置失败:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退出恢复模式
|
||||||
|
teaconst.IsRecoverMode = false
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
153
internal/web/actions/default/recover/validateApi.go
Normal file
153
internal/web/actions/default/recover/validateApi.go
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
package recover
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ValidateApiAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ValidateApiAction) RunPost(params struct {
|
||||||
|
Protocol string
|
||||||
|
Host string
|
||||||
|
Port string
|
||||||
|
NodeId string
|
||||||
|
NodeSecret string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
params.NodeId = strings.Trim(params.NodeId, "\"' ")
|
||||||
|
params.NodeSecret = strings.Trim(params.NodeSecret, "\"' ")
|
||||||
|
|
||||||
|
// 使用已有的API节点
|
||||||
|
params.Must.
|
||||||
|
Field("host", params.Host).
|
||||||
|
Require("请输入主机地址").
|
||||||
|
Field("port", params.Port).
|
||||||
|
Require("请输入服务端口").
|
||||||
|
Match(`^\d+$`, "服务端口只能是数字").
|
||||||
|
Field("nodeId", params.NodeId).
|
||||||
|
Require("请输入节点nodeId").
|
||||||
|
Field("nodeSecret", params.NodeSecret).
|
||||||
|
Require("请输入节点secret")
|
||||||
|
client, err := rpc.NewRPCClient(&configs.APIConfig{
|
||||||
|
RPC: struct {
|
||||||
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
}{
|
||||||
|
Endpoints: []string{params.Protocol + "://" + configutils.QuoteIP(params.Host) + ":" + params.Port},
|
||||||
|
},
|
||||||
|
NodeId: params.NodeId,
|
||||||
|
Secret: params.NodeSecret,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("host", "测试API节点时出错,请检查配置,错误信息:"+err.Error())
|
||||||
|
}
|
||||||
|
_, err = client.APINodeRPC().FindCurrentAPINodeVersion(client.APIContext(0), &pb.FindCurrentAPINodeVersionRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("host", "无法连接此API节点,错误信息:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// API节点列表
|
||||||
|
nodesResp, err := client.APINodeRPC().FindAllEnabledAPINodes(client.Context(0), &pb.FindAllEnabledAPINodesRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("获取API节点列表失败,错误信息:" + err.Error())
|
||||||
|
}
|
||||||
|
var hosts = []string{}
|
||||||
|
for _, node := range nodesResp.Nodes {
|
||||||
|
if !node.IsOn {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// http
|
||||||
|
if len(node.HttpJSON) > 0 {
|
||||||
|
var config = &serverconfigs.HTTPProtocolConfig{}
|
||||||
|
err = json.Unmarshal(node.HttpJSON, config)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("读取节点HTTP信息失败:" + err.Error())
|
||||||
|
}
|
||||||
|
for _, listen := range config.Listen {
|
||||||
|
if len(listen.Host) > 0 && !lists.ContainsString(hosts, listen.Host) {
|
||||||
|
hosts = append(hosts, listen.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https
|
||||||
|
if len(node.HttpsJSON) > 0 {
|
||||||
|
var config = &serverconfigs.HTTPSProtocolConfig{}
|
||||||
|
err = json.Unmarshal(node.HttpsJSON, config)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("读取节点HTTPS信息失败:" + err.Error())
|
||||||
|
}
|
||||||
|
for _, listen := range config.Listen {
|
||||||
|
if len(listen.Host) > 0 && !lists.ContainsString(hosts, listen.Host) {
|
||||||
|
hosts = append(hosts, listen.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restHTTP
|
||||||
|
if len(node.RestHTTPJSON) > 0 {
|
||||||
|
var config = &serverconfigs.HTTPProtocolConfig{}
|
||||||
|
err = json.Unmarshal(node.RestHTTPJSON, config)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("读取节点REST HTTP信息失败:" + err.Error())
|
||||||
|
}
|
||||||
|
for _, listen := range config.Listen {
|
||||||
|
if len(listen.Host) > 0 && !lists.ContainsString(hosts, listen.Host) {
|
||||||
|
hosts = append(hosts, listen.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restHTTPS
|
||||||
|
if len(node.RestHTTPSJSON) > 0 {
|
||||||
|
var config = &serverconfigs.HTTPSProtocolConfig{}
|
||||||
|
err = json.Unmarshal(node.RestHTTPSJSON, config)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("读取节点REST HTTPS信息失败:" + err.Error())
|
||||||
|
}
|
||||||
|
for _, listen := range config.Listen {
|
||||||
|
if len(listen.Host) > 0 && !lists.ContainsString(hosts, listen.Host) {
|
||||||
|
hosts = append(hosts, listen.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// access addrs
|
||||||
|
if len(node.AccessAddrsJSON) > 0 {
|
||||||
|
var addrs []*serverconfigs.NetworkAddressConfig
|
||||||
|
err = json.Unmarshal(node.AccessAddrsJSON, &addrs)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("读取节点访问地址失败:" + err.Error())
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if len(addr.Host) > 0 && !lists.ContainsString(hosts, addr.Host) {
|
||||||
|
hosts = append(hosts, addr.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["apiNode"] = maps.Map{
|
||||||
|
"protocol": params.Protocol,
|
||||||
|
"host": params.Host,
|
||||||
|
"port": params.Port,
|
||||||
|
"nodeId": params.NodeId,
|
||||||
|
"nodeSecret": params.NodeSecret,
|
||||||
|
"hosts": hosts,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -20,7 +20,10 @@ func (this *AddPortPopupAction) Init() {
|
|||||||
func (this *AddPortPopupAction) RunGet(params struct {
|
func (this *AddPortPopupAction) RunGet(params struct {
|
||||||
ServerType string
|
ServerType string
|
||||||
Protocol string
|
Protocol string
|
||||||
|
From string
|
||||||
}) {
|
}) {
|
||||||
|
this.Data["from"] = params.From
|
||||||
|
|
||||||
protocols := serverconfigs.AllServerProtocolsForType(params.ServerType)
|
protocols := serverconfigs.AllServerProtocolsForType(params.ServerType)
|
||||||
if len(params.Protocol) > 0 {
|
if len(params.Protocol) > 0 {
|
||||||
result := []maps.Map{}
|
result := []maps.Map{}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
DnsDomain string
|
DnsDomain string
|
||||||
Domains []string
|
Domains []string
|
||||||
AutoRenew bool
|
AutoRenew bool
|
||||||
|
AuthURL string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
@@ -123,6 +124,7 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
DnsDomain: dnsDomain,
|
DnsDomain: dnsDomain,
|
||||||
Domains: realDomains,
|
Domains: realDomains,
|
||||||
AutoRenew: params.AutoRenew,
|
AutoRenew: params.AutoRenew,
|
||||||
|
AuthURL: params.AuthURL,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
@@ -138,6 +140,7 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
DnsDomain: dnsDomain,
|
DnsDomain: dnsDomain,
|
||||||
Domains: realDomains,
|
Domains: realDomains,
|
||||||
AutoRenew: params.AutoRenew,
|
AutoRenew: params.AutoRenew,
|
||||||
|
AuthURL: params.AuthURL,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ func (this *UpdateTaskPopupAction) RunGet(params struct {
|
|||||||
"domains": task.Domains,
|
"domains": task.Domains,
|
||||||
"autoRenew": task.AutoRenew,
|
"autoRenew": task.AutoRenew,
|
||||||
"isOn": task.IsOn,
|
"isOn": task.IsOn,
|
||||||
|
"authURL": task.AuthURL,
|
||||||
"dnsProvider": dnsProviderMap,
|
"dnsProvider": dnsProviderMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +95,7 @@ func (this *UpdateTaskPopupAction) RunPost(params struct {
|
|||||||
DnsDomain string
|
DnsDomain string
|
||||||
Domains []string
|
Domains []string
|
||||||
AutoRenew bool
|
AutoRenew bool
|
||||||
|
AuthURL string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
@@ -146,6 +148,7 @@ func (this *UpdateTaskPopupAction) RunPost(params struct {
|
|||||||
DnsDomain: dnsDomain,
|
DnsDomain: dnsDomain,
|
||||||
Domains: realDomains,
|
Domains: realDomains,
|
||||||
AutoRenew: params.AutoRenew,
|
AutoRenew: params.AutoRenew,
|
||||||
|
AuthURL: params.AuthURL,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreateSetPopupAction struct {
|
type CreateSetPopupAction struct {
|
||||||
@@ -53,6 +52,7 @@ func (this *CreateSetPopupAction) RunGet(params struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 所有可选的动作
|
||||||
actionMaps := []maps.Map{}
|
actionMaps := []maps.Map{}
|
||||||
for _, action := range firewallconfigs.AllActions {
|
for _, action := range firewallconfigs.AllActions {
|
||||||
actionMaps = append(actionMaps, maps.Map{
|
actionMaps = append(actionMaps, maps.Map{
|
||||||
@@ -69,10 +69,10 @@ func (this *CreateSetPopupAction) RunGet(params struct {
|
|||||||
func (this *CreateSetPopupAction) RunPost(params struct {
|
func (this *CreateSetPopupAction) RunPost(params struct {
|
||||||
GroupId int64
|
GroupId int64
|
||||||
|
|
||||||
Name string
|
Name string
|
||||||
RulesJSON []byte
|
RulesJSON []byte
|
||||||
Connector string
|
Connector string
|
||||||
Action string
|
ActionsJSON []byte
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
@@ -96,32 +96,34 @@ func (this *CreateSetPopupAction) RunPost(params struct {
|
|||||||
err = json.Unmarshal(params.RulesJSON, &rules)
|
err = json.Unmarshal(params.RulesJSON, &rules)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if len(rules) == 0 {
|
if len(rules) == 0 {
|
||||||
this.Fail("请添加至少一个规则")
|
this.Fail("请添加至少一个规则")
|
||||||
}
|
}
|
||||||
|
|
||||||
setConfig := &firewallconfigs.HTTPFirewallRuleSet{
|
var actionConfigs = []*firewallconfigs.HTTPFirewallActionConfig{}
|
||||||
Id: 0,
|
if len(params.ActionsJSON) > 0 {
|
||||||
IsOn: true,
|
err = json.Unmarshal(params.ActionsJSON, &actionConfigs)
|
||||||
Name: params.Name,
|
if err != nil {
|
||||||
Code: "",
|
this.ErrorPage(err)
|
||||||
Description: "",
|
return
|
||||||
Connector: params.Connector,
|
}
|
||||||
RuleRefs: nil,
|
}
|
||||||
Rules: rules,
|
if len(actionConfigs) == 0 {
|
||||||
Action: params.Action,
|
this.Fail("请添加至少一个动作")
|
||||||
ActionOptions: maps.Map{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range this.ParamsMap {
|
setConfig := &firewallconfigs.HTTPFirewallRuleSet{
|
||||||
if len(v) == 0 {
|
Id: 0,
|
||||||
continue
|
IsOn: true,
|
||||||
}
|
Name: params.Name,
|
||||||
index := strings.Index(k, "action_")
|
Code: "",
|
||||||
if index > -1 {
|
Description: "",
|
||||||
setConfig.ActionOptions[k[len("action_"):]] = v[0]
|
Connector: params.Connector,
|
||||||
}
|
RuleRefs: nil,
|
||||||
|
Rules: rules,
|
||||||
|
Actions: actionConfigs,
|
||||||
}
|
}
|
||||||
|
|
||||||
setConfigJSON, err := json.Marshal(setConfig)
|
setConfigJSON, err := json.Marshal(setConfig)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
"github.com/iwind/TeaGo/lists"
|
"github.com/iwind/TeaGo/lists"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,31 +53,19 @@ func (this *GroupAction) RunGet(params struct {
|
|||||||
set := v.(*firewallconfigs.HTTPFirewallRuleSet)
|
set := v.(*firewallconfigs.HTTPFirewallRuleSet)
|
||||||
|
|
||||||
// 动作说明
|
// 动作说明
|
||||||
actionLinks := []maps.Map{}
|
var actionMaps = []maps.Map{}
|
||||||
if set.Action == firewallconfigs.HTTPFirewallActionGoGroup {
|
for _, action := range set.Actions {
|
||||||
nextGroup := firewallPolicy.FindRuleGroup(set.ActionOptions.GetInt64("groupId"))
|
def := firewallconfigs.FindActionDefinition(action.Code)
|
||||||
if nextGroup != nil {
|
if def == nil {
|
||||||
actionLinks = append(actionLinks, maps.Map{
|
continue
|
||||||
"name": nextGroup.Name,
|
|
||||||
"url": "/servers/components/waf/group?firewallPolicyId=" + strconv.FormatInt(params.FirewallPolicyId, 10) + "&type=" + params.Type + "&groupId=" + strconv.FormatInt(nextGroup.Id, 10),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else if set.Action == firewallconfigs.HTTPFirewallActionGoSet {
|
|
||||||
nextGroup := firewallPolicy.FindRuleGroup(set.ActionOptions.GetInt64("groupId"))
|
|
||||||
if nextGroup != nil {
|
|
||||||
actionLinks = append(actionLinks, maps.Map{
|
|
||||||
"name": nextGroup.Name,
|
|
||||||
"url": "/servers/components/waf/group?firewallPolicyId=" + strconv.FormatInt(params.FirewallPolicyId, 10) + "&type=" + params.Type + "&groupId=" + strconv.FormatInt(nextGroup.Id, 10),
|
|
||||||
})
|
|
||||||
|
|
||||||
nextSet := nextGroup.FindRuleSet(set.ActionOptions.GetInt64("setId"))
|
actionMaps = append(actionMaps, maps.Map{
|
||||||
if nextSet != nil {
|
"code": strings.ToUpper(action.Code),
|
||||||
actionLinks = append(actionLinks, maps.Map{
|
"name": def.Name,
|
||||||
"name": nextSet.Name,
|
"category": def.Category,
|
||||||
"url": "/servers/components/waf/group?firewallPolicyId=" + strconv.FormatInt(params.FirewallPolicyId, 10) + "&type=" + params.Type + "&groupId=" + strconv.FormatInt(nextGroup.Id, 10),
|
"options": action.Options,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return maps.Map{
|
return maps.Map{
|
||||||
@@ -93,14 +80,12 @@ func (this *GroupAction) RunGet(params struct {
|
|||||||
"value": rule.Value,
|
"value": rule.Value,
|
||||||
"isCaseInsensitive": rule.IsCaseInsensitive,
|
"isCaseInsensitive": rule.IsCaseInsensitive,
|
||||||
"isComposed": firewallconfigs.CheckCheckpointIsComposed(rule.Prefix()),
|
"isComposed": firewallconfigs.CheckCheckpointIsComposed(rule.Prefix()),
|
||||||
|
"checkpointOptions": rule.CheckpointOptions,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"isOn": set.IsOn,
|
"isOn": set.IsOn,
|
||||||
"action": strings.ToUpper(set.Action),
|
"actions": actionMaps,
|
||||||
"actionOptions": set.ActionOptions,
|
"connector": strings.ToUpper(set.Connector),
|
||||||
"actionName": firewallconfigs.FindActionName(set.Action),
|
|
||||||
"actionLinks": actionLinks,
|
|
||||||
"connector": strings.ToUpper(set.Connector),
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ func (this *ListsAction) RunGet(params struct {
|
|||||||
Type string
|
Type string
|
||||||
}) {
|
}) {
|
||||||
this.Data["subMenuItem"] = params.Type
|
this.Data["subMenuItem"] = params.Type
|
||||||
|
this.Data["type"] = params.Type
|
||||||
|
|
||||||
listId, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyIPListIdWithType(this.AdminContext(), params.FirewallPolicyId, params.Type)
|
listId, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyIPListIdWithType(this.AdminContext(), params.FirewallPolicyId, params.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpdateSetPopupAction struct {
|
type UpdateSetPopupAction struct {
|
||||||
@@ -79,6 +78,14 @@ func (this *UpdateSetPopupAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
this.Data["setConfig"] = setConfig
|
this.Data["setConfig"] = setConfig
|
||||||
|
|
||||||
|
// action configs
|
||||||
|
actionConfigs, err := dao.SharedHTTPFirewallPolicyDAO.FindHTTPFirewallActionConfigs(this.AdminContext(), setConfig.Actions)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["actionConfigs"] = actionConfigs
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,10 +93,10 @@ func (this *UpdateSetPopupAction) RunPost(params struct {
|
|||||||
GroupId int64
|
GroupId int64
|
||||||
SetId int64
|
SetId int64
|
||||||
|
|
||||||
Name string
|
Name string
|
||||||
RulesJSON []byte
|
RulesJSON []byte
|
||||||
Connector string
|
Connector string
|
||||||
Action string
|
ActionsJSON []byte
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
@@ -115,26 +122,28 @@ func (this *UpdateSetPopupAction) RunPost(params struct {
|
|||||||
err = json.Unmarshal(params.RulesJSON, &rules)
|
err = json.Unmarshal(params.RulesJSON, &rules)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if len(rules) == 0 {
|
if len(rules) == 0 {
|
||||||
this.Fail("请添加至少一个规则")
|
this.Fail("请添加至少一个规则")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var actionConfigs = []*firewallconfigs.HTTPFirewallActionConfig{}
|
||||||
|
if len(params.ActionsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(params.ActionsJSON, &actionConfigs)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(actionConfigs) == 0 {
|
||||||
|
this.Fail("请添加至少一个动作")
|
||||||
|
}
|
||||||
|
|
||||||
setConfig.Name = params.Name
|
setConfig.Name = params.Name
|
||||||
setConfig.Connector = params.Connector
|
setConfig.Connector = params.Connector
|
||||||
setConfig.Rules = rules
|
setConfig.Rules = rules
|
||||||
setConfig.Action = params.Action
|
setConfig.Actions = actionConfigs
|
||||||
setConfig.ActionOptions = maps.Map{}
|
|
||||||
|
|
||||||
for k, v := range this.ParamsMap {
|
|
||||||
if len(v) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
index := strings.Index(k, "action_")
|
|
||||||
if index > -1 {
|
|
||||||
setConfig.ActionOptions[k[len("action_"):]] = v[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setConfigJSON, err := json.Marshal(setConfig)
|
setConfigJSON, err := json.Marshal(setConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -5,11 +5,14 @@ import (
|
|||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
"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/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/logs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -68,6 +71,9 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
CertIdsJSON []byte
|
CertIdsJSON []byte
|
||||||
Origins string
|
Origins string
|
||||||
|
|
||||||
|
AccessLogIsOn bool
|
||||||
|
WebsocketIsOn bool
|
||||||
|
|
||||||
WebRoot string
|
WebRoot string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
@@ -415,6 +421,70 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var serverId = createResp.ServerId
|
||||||
|
|
||||||
|
// 开启访问日志和Websocket
|
||||||
|
if params.ServerType == serverconfigs.ServerTypeHTTPProxy {
|
||||||
|
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), serverId)
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err)
|
||||||
|
} else {
|
||||||
|
// 访问日志
|
||||||
|
if params.AccessLogIsOn {
|
||||||
|
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebAccessLog(this.AdminContext(), &pb.UpdateHTTPWebAccessLogRequest{
|
||||||
|
WebId: webConfig.Id,
|
||||||
|
AccessLogJSON: []byte(`{
|
||||||
|
"isPrior": false,
|
||||||
|
"isOn": true,
|
||||||
|
"fields": [],
|
||||||
|
"status1": true,
|
||||||
|
"status2": true,
|
||||||
|
"status3": true,
|
||||||
|
"status4": true,
|
||||||
|
"status5": true,
|
||||||
|
|
||||||
|
"storageOnly": false,
|
||||||
|
"storagePolicies": [],
|
||||||
|
|
||||||
|
"firewallOnly": false
|
||||||
|
}`),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// websocket
|
||||||
|
if params.WebsocketIsOn {
|
||||||
|
createWebSocketResp, err := this.RPC().HTTPWebsocketRPC().CreateHTTPWebsocket(this.AdminContext(), &pb.CreateHTTPWebsocketRequest{
|
||||||
|
HandshakeTimeoutJSON: []byte(`{
|
||||||
|
"count": 30,
|
||||||
|
"unit": "second"
|
||||||
|
}`),
|
||||||
|
AllowAllOrigins: true,
|
||||||
|
AllowedOrigins: nil,
|
||||||
|
RequestSameOrigin: true,
|
||||||
|
RequestOrigin: "",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err)
|
||||||
|
} else {
|
||||||
|
websocketId := createWebSocketResp.WebsocketId
|
||||||
|
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebWebsocket(this.AdminContext(), &pb.UpdateHTTPWebWebsocketRequest{
|
||||||
|
WebId: webConfig.Id,
|
||||||
|
WebsocketJSON: []byte(` {
|
||||||
|
"isPrior": false,
|
||||||
|
"isOn": true,
|
||||||
|
"websocketId": ` + types.String(websocketId) + `
|
||||||
|
}`),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 创建日志
|
// 创建日志
|
||||||
defer this.CreateLog(oplogs.LevelInfo, "创建代理服务 %d", createResp.ServerId)
|
defer this.CreateLog(oplogs.LevelInfo, "创建代理服务 %d", createResp.ServerId)
|
||||||
|
|||||||
55
internal/web/actions/default/servers/ipbox/index.go
Normal file
55
internal/web/actions/default/servers/ipbox/index.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// 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"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
Ip string
|
||||||
|
}) {
|
||||||
|
this.Data["ip"] = params.Ip
|
||||||
|
|
||||||
|
accessLogsResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||||
|
Day: timeutil.Format("Ymd"),
|
||||||
|
Keyword: "ip:" + params.Ip,
|
||||||
|
Size: 10,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var accessLogs = accessLogsResp.HttpAccessLogs
|
||||||
|
if len(accessLogs) == 0 {
|
||||||
|
// 查询昨天
|
||||||
|
accessLogsResp, err = this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||||
|
Day: timeutil.Format("Ymd", time.Now().AddDate(0, 0, -1)),
|
||||||
|
Keyword: "ip:" + params.Ip,
|
||||||
|
Size: 10,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
accessLogs = accessLogsResp.HttpAccessLogs
|
||||||
|
|
||||||
|
if len(accessLogs) == 0 {
|
||||||
|
accessLogs = []*pb.HTTPAccessLog{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Data["accessLogs"] = accessLogs
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
19
internal/web/actions/default/servers/ipbox/init.go
Normal file
19
internal/web/actions/default/servers/ipbox/init.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// 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/ipbox").
|
||||||
|
Get("", new(IndexAction)).
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccessLogsPopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *AccessLogsPopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *AccessLogsPopupAction) RunGet(params struct {
|
||||||
|
ItemId int64
|
||||||
|
}) {
|
||||||
|
itemResp, err := this.RPC().IPItemRPC().FindEnabledIPItem(this.AdminContext(), &pb.FindEnabledIPItemRequest{IpItemId: params.ItemId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var item = itemResp.IpItem
|
||||||
|
if item == nil {
|
||||||
|
this.NotFound("ipItem", params.ItemId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["ipFrom"] = item.IpFrom
|
||||||
|
this.Data["ipTo"] = item.IpTo
|
||||||
|
|
||||||
|
accessLogsResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||||
|
Day: timeutil.Format("Ymd"),
|
||||||
|
Keyword: "ip:" + item.IpFrom + "," + item.IpTo,
|
||||||
|
Size: 10,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var accessLogs = accessLogsResp.HttpAccessLogs
|
||||||
|
if len(accessLogs) == 0 {
|
||||||
|
accessLogs = []*pb.HTTPAccessLog{}
|
||||||
|
}
|
||||||
|
this.Data["accessLogs"] = accessLogs
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BindHTTPFirewallPopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BindHTTPFirewallPopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BindHTTPFirewallPopupAction) RunGet(params struct {
|
||||||
|
HttpFirewallPolicyId int64
|
||||||
|
Type string
|
||||||
|
}) {
|
||||||
|
this.Data["httpFirewallPolicyId"] = params.HttpFirewallPolicyId
|
||||||
|
|
||||||
|
// 获取已经选中的名单IDs
|
||||||
|
var selectedIds = []int64{}
|
||||||
|
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if inboundConfig != nil {
|
||||||
|
for _, ref := range inboundConfig.PublicAllowListRefs {
|
||||||
|
selectedIds = append(selectedIds, ref.ListId)
|
||||||
|
}
|
||||||
|
for _, ref := range inboundConfig.PublicDenyListRefs {
|
||||||
|
selectedIds = append(selectedIds, ref.ListId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公共的名单
|
||||||
|
countResp, err := this.RPC().IPListRPC().CountAllEnabledIPLists(this.AdminContext(), &pb.CountAllEnabledIPListsRequest{
|
||||||
|
Type: params.Type,
|
||||||
|
IsPublic: true,
|
||||||
|
Keyword: "",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
count := countResp.Count
|
||||||
|
page := this.NewPage(count)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
listsResp, err := this.RPC().IPListRPC().ListEnabledIPLists(this.AdminContext(), &pb.ListEnabledIPListsRequest{
|
||||||
|
Type: params.Type,
|
||||||
|
IsPublic: true,
|
||||||
|
Keyword: "",
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var listMaps = []maps.Map{}
|
||||||
|
for _, list := range listsResp.IpLists {
|
||||||
|
// 包含的IP数量
|
||||||
|
countItemsResp, err := this.RPC().IPItemRPC().CountIPItemsWithListId(this.AdminContext(), &pb.CountIPItemsWithListIdRequest{IpListId: list.Id})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var countItems = countItemsResp.Count
|
||||||
|
|
||||||
|
listMaps = append(listMaps, maps.Map{
|
||||||
|
"id": list.Id,
|
||||||
|
"isOn": list.IsOn,
|
||||||
|
"name": list.Name,
|
||||||
|
"description": list.Description,
|
||||||
|
"countItems": countItems,
|
||||||
|
"type": list.Type,
|
||||||
|
"isSelected": lists.ContainsInt64(selectedIds, list.Id),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["lists"] = listMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BindHTTPFirewallPopupAction) RunPost(params struct {
|
||||||
|
HttpFirewallPolicyId int64
|
||||||
|
ListId int64
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("绑定IP名单 %d 到WAF策略 %d", params.ListId, params.HttpFirewallPolicyId)
|
||||||
|
|
||||||
|
// List类型
|
||||||
|
listResp, err := this.RPC().IPListRPC().FindEnabledIPList(this.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: params.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var list = listResp.IpList
|
||||||
|
if list == nil {
|
||||||
|
this.Fail("找不到要使用的IP名单")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已经绑定的
|
||||||
|
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if inboundConfig == nil {
|
||||||
|
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||||
|
}
|
||||||
|
inboundConfig.AddPublicList(list.Id, list.Type)
|
||||||
|
|
||||||
|
inboundJSON, err := json.Marshal(inboundConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallInboundConfig(this.AdminContext(), &pb.UpdateHTTPFirewallInboundConfigRequest{
|
||||||
|
HttpFirewallPolicyId: params.HttpFirewallPolicyId,
|
||||||
|
InboundJSON: inboundJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
103
internal/web/actions/default/servers/iplists/createIPPopup.go
Normal file
103
internal/web/actions/default/servers/iplists/createIPPopup.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
|
"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/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateIPPopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateIPPopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateIPPopupAction) RunGet(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
this.Data["listId"] = params.ListId
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateIPPopupAction) RunPost(params struct {
|
||||||
|
ListId int64
|
||||||
|
IpFrom string
|
||||||
|
IpTo string
|
||||||
|
ExpiredAt int64
|
||||||
|
Reason string
|
||||||
|
Type string
|
||||||
|
EventLevel string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
// 校验IPList
|
||||||
|
existsResp, err := this.RPC().IPListRPC().ExistsEnabledIPList(this.AdminContext(), &pb.ExistsEnabledIPListRequest{IpListId: params.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !existsResp.Exists {
|
||||||
|
this.Fail("IP名单不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch params.Type {
|
||||||
|
case "ipv4":
|
||||||
|
params.Must.
|
||||||
|
Field("ipFrom", params.IpFrom).
|
||||||
|
Require("请输入开始IP")
|
||||||
|
|
||||||
|
// 校验IP格式(ipFrom/ipTo)
|
||||||
|
var ipFromLong uint64
|
||||||
|
if !utils.IsIPv4(params.IpFrom) {
|
||||||
|
this.Fail("请输入正确的开始IP")
|
||||||
|
}
|
||||||
|
ipFromLong = utils.IP2Long(params.IpFrom)
|
||||||
|
|
||||||
|
var ipToLong uint64
|
||||||
|
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
|
||||||
|
ipToLong = utils.IP2Long(params.IpTo)
|
||||||
|
this.Fail("请输入正确的结束IP")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
|
||||||
|
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
|
||||||
|
}
|
||||||
|
case "ipv6":
|
||||||
|
params.Must.
|
||||||
|
Field("ipFrom", params.IpFrom).
|
||||||
|
Require("请输入IP")
|
||||||
|
|
||||||
|
// 校验IP格式(ipFrom)
|
||||||
|
if !utils.IsIPv6(params.IpFrom) {
|
||||||
|
this.Fail("请输入正确的IPv6地址")
|
||||||
|
}
|
||||||
|
case "all":
|
||||||
|
params.IpFrom = "0.0.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
createResp, err := this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
|
||||||
|
IpListId: params.ListId,
|
||||||
|
IpFrom: params.IpFrom,
|
||||||
|
IpTo: params.IpTo,
|
||||||
|
ExpiredAt: params.ExpiredAt,
|
||||||
|
Reason: params.Reason,
|
||||||
|
Type: params.Type,
|
||||||
|
EventLevel: params.EventLevel,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
itemId := createResp.IpItemId
|
||||||
|
|
||||||
|
// 日志
|
||||||
|
defer this.CreateLog(oplogs.LevelInfo, "在IP名单中添加IP %d", itemId)
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
64
internal/web/actions/default/servers/iplists/createPopup.go
Normal file
64
internal/web/actions/default/servers/iplists/createPopup.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreatePopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunGet(params struct {
|
||||||
|
Type string
|
||||||
|
}) {
|
||||||
|
this.Data["type"] = params.Type
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunPost(params struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Description string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
var listId int64 = 0
|
||||||
|
defer func() {
|
||||||
|
defer this.CreateLogInfo("创建IP名单 %d", listId)
|
||||||
|
}()
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("name", params.Name).
|
||||||
|
Require("请输入名称")
|
||||||
|
|
||||||
|
createResp, err := this.RPC().IPListRPC().CreateIPList(this.AdminContext(), &pb.CreateIPListRequest{
|
||||||
|
Type: params.Type,
|
||||||
|
Name: params.Name,
|
||||||
|
Code: "",
|
||||||
|
TimeoutJSON: nil,
|
||||||
|
IsPublic: true,
|
||||||
|
Description: params.Description,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
listId = createResp.IpListId
|
||||||
|
|
||||||
|
this.Data["list"] = maps.Map{
|
||||||
|
"type": params.Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
27
internal/web/actions/default/servers/iplists/delete.go
Normal file
27
internal/web/actions/default/servers/iplists/delete.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
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 {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("删除IP名单 %d", params.ListId)
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
_, err := this.RPC().IPListRPC().DeleteIPList(this.AdminContext(), &pb.DeleteIPListRequest{IpListId: params.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
26
internal/web/actions/default/servers/iplists/deleteIP.go
Normal file
26
internal/web/actions/default/servers/iplists/deleteIP.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteIPAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DeleteIPAction) RunPost(params struct {
|
||||||
|
ItemId int64
|
||||||
|
}) {
|
||||||
|
// 日志
|
||||||
|
defer this.CreateLog(oplogs.LevelInfo, "从IP名单中删除IP %d", params.ItemId)
|
||||||
|
|
||||||
|
_, err := this.RPC().IPItemRPC().DeleteIPItem(this.AdminContext(), &pb.DeleteIPItemRequest{IpItemId: params.ItemId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
25
internal/web/actions/default/servers/iplists/export.go
Normal file
25
internal/web/actions/default/servers/iplists/export.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
|
||||||
|
type ExportAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ExportAction) Init() {
|
||||||
|
this.Nav("", "", "export")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ExportAction) RunGet(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
err := InitIPList(this.Parent(), params.ListId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
57
internal/web/actions/default/servers/iplists/exportData.go
Normal file
57
internal/web/actions/default/servers/iplists/exportData.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExportDataAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ExportDataAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ExportDataAction) RunGet(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("导出IP名单 %d", params.ListId)
|
||||||
|
|
||||||
|
resp := &pb.ListIPItemsWithListIdResponse{}
|
||||||
|
var offset int64 = 0
|
||||||
|
var size int64 = 1000
|
||||||
|
for {
|
||||||
|
itemsResp, err := this.RPC().IPItemRPC().ListIPItemsWithListId(this.AdminContext(), &pb.ListIPItemsWithListIdRequest{
|
||||||
|
IpListId: params.ListId,
|
||||||
|
Offset: offset,
|
||||||
|
Size: size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(itemsResp.IpItems) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, item := range itemsResp.IpItems {
|
||||||
|
resp.IpItems = append(resp.IpItems, item)
|
||||||
|
}
|
||||||
|
offset += size
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := proto.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.AddHeader("Content-Disposition", "attachment; filename=\"ip-list-"+numberutils.FormatInt64(params.ListId)+".data\";")
|
||||||
|
this.AddHeader("Content-Length", strconv.Itoa(len(data)))
|
||||||
|
this.Write(data)
|
||||||
|
}
|
||||||
59
internal/web/actions/default/servers/iplists/httpFirewall.go
Normal file
59
internal/web/actions/default/servers/iplists/httpFirewall.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ipconfigs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HttpFirewallAction 显示已经绑定的IP名单
|
||||||
|
type HttpFirewallAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *HttpFirewallAction) RunPost(params struct {
|
||||||
|
HttpFirewallPolicyId int64
|
||||||
|
Type string
|
||||||
|
}) {
|
||||||
|
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if inboundConfig == nil {
|
||||||
|
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||||
|
}
|
||||||
|
var refs []*ipconfigs.IPListRef
|
||||||
|
switch params.Type {
|
||||||
|
case ipconfigs.IPListTypeBlack:
|
||||||
|
refs = inboundConfig.PublicDenyListRefs
|
||||||
|
case ipconfigs.IPListTypeWhite:
|
||||||
|
refs = inboundConfig.PublicAllowListRefs
|
||||||
|
}
|
||||||
|
|
||||||
|
listMaps := []maps.Map{}
|
||||||
|
for _, ref := range refs {
|
||||||
|
listResp, err := this.RPC().IPListRPC().FindEnabledIPList(this.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: ref.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var list = listResp.IpList
|
||||||
|
if list == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
listMaps = append(listMaps, maps.Map{
|
||||||
|
"id": list.Id,
|
||||||
|
"name": list.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["lists"] = listMaps
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
87
internal/web/actions/default/servers/iplists/import.go
Normal file
87
internal/web/actions/default/servers/iplists/import.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ImportAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ImportAction) Init() {
|
||||||
|
this.Nav("", "", "import")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ImportAction) RunGet(params struct {
|
||||||
|
ListId int64
|
||||||
|
}) {
|
||||||
|
err := InitIPList(this.Parent(), params.ListId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ImportAction) RunPost(params struct {
|
||||||
|
ListId int64
|
||||||
|
File *actions.File
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("导入IP名单 %d", params.ListId)
|
||||||
|
|
||||||
|
existsResp, err := this.RPC().IPListRPC().ExistsEnabledIPList(this.AdminContext(), &pb.ExistsEnabledIPListRequest{IpListId: params.ListId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !existsResp.Exists {
|
||||||
|
this.Fail("IP名单不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.File == nil {
|
||||||
|
this.Fail("请选择要导入的IP文件")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := params.File.Read()
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp := &pb.ListIPItemsWithListIdResponse{}
|
||||||
|
err = proto.Unmarshal(data, resp)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("导入失败,文件格式错误:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var count = 0
|
||||||
|
var countIgnore = 0
|
||||||
|
for _, item := range resp.IpItems {
|
||||||
|
_, err = this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
|
||||||
|
IpListId: params.ListId,
|
||||||
|
IpFrom: item.IpFrom,
|
||||||
|
IpTo: item.IpTo,
|
||||||
|
ExpiredAt: item.ExpiredAt,
|
||||||
|
Reason: item.Reason,
|
||||||
|
Type: item.Type,
|
||||||
|
EventLevel: item.EventLevel,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("导入过程中出错:" + err.Error())
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["count"] = count
|
||||||
|
this.Data["countIgnore"] = countIgnore
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
76
internal/web/actions/default/servers/iplists/index.go
Normal file
76
internal/web/actions/default/servers/iplists/index.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ipconfigs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "", "index")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
Type string
|
||||||
|
Keyword string
|
||||||
|
}) {
|
||||||
|
if len(params.Type) == 0 {
|
||||||
|
params.Type = ipconfigs.IPListTypeBlack
|
||||||
|
}
|
||||||
|
this.Data["type"] = params.Type
|
||||||
|
this.Data["keyword"] = params.Keyword
|
||||||
|
|
||||||
|
countResp, err := this.RPC().IPListRPC().CountAllEnabledIPLists(this.AdminContext(), &pb.CountAllEnabledIPListsRequest{
|
||||||
|
Type: params.Type,
|
||||||
|
IsPublic: true,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
count := countResp.Count
|
||||||
|
page := this.NewPage(count)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
listsResp, err := this.RPC().IPListRPC().ListEnabledIPLists(this.AdminContext(), &pb.ListEnabledIPListsRequest{
|
||||||
|
Type: params.Type,
|
||||||
|
IsPublic: true,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var listMaps = []maps.Map{}
|
||||||
|
for _, list := range listsResp.IpLists {
|
||||||
|
// 包含的IP数量
|
||||||
|
countItemsResp, err := this.RPC().IPItemRPC().CountIPItemsWithListId(this.AdminContext(), &pb.CountIPItemsWithListIdRequest{IpListId: list.Id})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var countItems = countItemsResp.Count
|
||||||
|
|
||||||
|
listMaps = append(listMaps, maps.Map{
|
||||||
|
"id": list.Id,
|
||||||
|
"isOn": list.IsOn,
|
||||||
|
"name": list.Name,
|
||||||
|
"description": list.Description,
|
||||||
|
"countItems": countItems,
|
||||||
|
"type": list.Type,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["lists"] = listMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
44
internal/web/actions/default/servers/iplists/init.go
Normal file
44
internal/web/actions/default/servers/iplists/init.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package iplists
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
|
"github.com/iwind/TeaGo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
|
server.
|
||||||
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
|
||||||
|
Data("teaMenu", "servers").
|
||||||
|
Data("teaSubMenu", "iplist").
|
||||||
|
Prefix("/servers/iplists").
|
||||||
|
Get("", new(IndexAction)).
|
||||||
|
GetPost("/createPopup", new(CreatePopupAction)).
|
||||||
|
Get("/list", new(ListAction)).
|
||||||
|
GetPost("/import", new(ImportAction)).
|
||||||
|
GetPost("/export", new(ExportAction)).
|
||||||
|
Get("/exportData", new(ExportDataAction)).
|
||||||
|
Post("/delete", new(DeleteAction)).
|
||||||
|
GetPost("/test", new(TestAction)).
|
||||||
|
GetPost("/update", new(UpdateAction)).
|
||||||
|
Get("/items", new(ItemsAction)).
|
||||||
|
Get("/selectPopup", new(SelectPopupAction)).
|
||||||
|
|
||||||
|
// IP相关
|
||||||
|
GetPost("/createIPPopup", new(CreateIPPopupAction)).
|
||||||
|
GetPost("/updateIPPopup", new(UpdateIPPopupAction)).
|
||||||
|
Post("/deleteIP", new(DeleteIPAction)).
|
||||||
|
Get("/accessLogsPopup", new(AccessLogsPopupAction)).
|
||||||
|
|
||||||
|
// 防火墙
|
||||||
|
GetPost("/bindHTTPFirewallPopup", new(BindHTTPFirewallPopupAction)).
|
||||||
|
Post("/unbindHTTPFirewall", new(UnbindHTTPFirewallAction)).
|
||||||
|
Post("/httpFirewall", new(HttpFirewallAction)).
|
||||||
|
|
||||||
|
// 选项数据
|
||||||
|
Post("/levelOptions", new(LevelOptionsAction)).
|
||||||
|
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user