mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-20 16:20:27 +08:00
实现缓存策略的部分功能
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
rpc:
|
rpc:
|
||||||
endpoints: [ "127.0.0.1:8003" ]
|
endpoints: [ "http://127.0.0.1:8003" ]
|
||||||
nodeId: ""
|
nodeId: ""
|
||||||
secret: ""
|
secret: ""
|
||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/rands"
|
"github.com/iwind/TeaGo/rands"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,7 +31,19 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
|
|||||||
|
|
||||||
conns := []*grpc.ClientConn{}
|
conns := []*grpc.ClientConn{}
|
||||||
for _, endpoint := range apiConfig.RPC.Endpoints {
|
for _, endpoint := range apiConfig.RPC.Endpoints {
|
||||||
conn, err := grpc.Dial(endpoint, grpc.WithInsecure())
|
u, err := url.Parse(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("parse endpoint failed: " + err.Error())
|
||||||
|
}
|
||||||
|
var conn *grpc.ClientConn
|
||||||
|
if u.Scheme == "http" {
|
||||||
|
conn, err = grpc.Dial(u.Host, grpc.WithInsecure())
|
||||||
|
} else if u.Scheme == "https" {
|
||||||
|
// TODO 暂不支持HTTPS
|
||||||
|
conn, err = grpc.Dial(u.Host)
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("parse endpoint failed: invalid scheme '" + u.Scheme + "'")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
_ "github.com/iwind/TeaGo/bootstrap"
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -31,3 +31,66 @@ func TestRPCClient_NodeRPC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log(resp)
|
t.Log(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRPC_Dial_HTTP(t *testing.T) {
|
||||||
|
client, err := NewRPCClient(&configs.APIConfig{
|
||||||
|
RPC: struct {
|
||||||
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
}{
|
||||||
|
Endpoints: []string{"127.0.0.1:8003"},
|
||||||
|
},
|
||||||
|
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||||
|
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.NodeRPC().FindEnabledNode(client.Context(1), &pb.FindEnabledNodeRequest{NodeId: 4})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(resp.Node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRPC_Dial_HTTP_2(t *testing.T) {
|
||||||
|
client, err := NewRPCClient(&configs.APIConfig{
|
||||||
|
RPC: struct {
|
||||||
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
}{
|
||||||
|
Endpoints: []string{"http://127.0.0.1:8003"},
|
||||||
|
},
|
||||||
|
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||||
|
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.NodeRPC().FindEnabledNode(client.Context(1), &pb.FindEnabledNodeRequest{NodeId: 4})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(resp.Node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRPC_Dial_HTTPS(t *testing.T) {
|
||||||
|
client, err := NewRPCClient(&configs.APIConfig{
|
||||||
|
RPC: struct {
|
||||||
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
}{
|
||||||
|
Endpoints: []string{"https://127.0.0.1:8004"},
|
||||||
|
},
|
||||||
|
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||||
|
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.NodeRPC().FindEnabledNode(client.Context(1), &pb.FindEnabledNodeRequest{NodeId: 4})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(resp.Node)
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"isOn": node.IsOn,
|
"isOn": node.IsOn,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
"host": node.Host,
|
"accessAddrs": node.AccessAddrs,
|
||||||
"port": node.Port,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,26 +23,112 @@ func (this *CreateAction) RunGet(params struct{}) {
|
|||||||
|
|
||||||
func (this *CreateAction) RunPost(params struct {
|
func (this *CreateAction) RunPost(params struct {
|
||||||
Name string
|
Name string
|
||||||
Host string
|
|
||||||
Port int
|
|
||||||
Description string
|
Description string
|
||||||
|
ListensJSON []byte
|
||||||
|
CertIdsJSON []byte
|
||||||
|
AccessAddrsJSON []byte
|
||||||
|
IsOn bool
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("name", params.Name).
|
Field("name", params.Name).
|
||||||
Require("请输入API节点").
|
Require("请输入API节点名称")
|
||||||
Field("host", params.Host).
|
|
||||||
Require("请输入主机地址").
|
|
||||||
Field("port", params.Port).
|
|
||||||
Gt(0, "端口不能小于1").
|
|
||||||
Lte(65535, "端口不能大于65535")
|
|
||||||
|
|
||||||
_, err := this.RPC().APINodeRPC().CreateAPINode(this.AdminContext(), &pb.CreateAPINodeRequest{
|
httpConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||||
|
httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
|
||||||
|
|
||||||
|
// 监听地址
|
||||||
|
listens := []*serverconfigs.NetworkAddressConfig{}
|
||||||
|
err := json.Unmarshal(params.ListensJSON, &listens)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(listens) == 0 {
|
||||||
|
this.Fail("请添加至少一个进程监听地址")
|
||||||
|
}
|
||||||
|
for _, addr := range listens {
|
||||||
|
if addr.Protocol.IsHTTPFamily() {
|
||||||
|
httpConfig.IsOn = true
|
||||||
|
httpConfig.Listen = append(httpConfig.Listen, addr)
|
||||||
|
} else if addr.Protocol.IsHTTPSFamily() {
|
||||||
|
httpsConfig.IsOn = true
|
||||||
|
httpsConfig.Listen = append(httpsConfig.Listen, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 证书
|
||||||
|
certIds := []int64{}
|
||||||
|
if len(params.CertIdsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(params.CertIdsJSON, &certIds)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if httpsConfig.IsOn && len(httpsConfig.Listen) > 0 && len(certIds) == 0 {
|
||||||
|
this.Fail("请添加至少一个证书")
|
||||||
|
}
|
||||||
|
|
||||||
|
certRefs := []*sslconfigs.SSLCertRef{}
|
||||||
|
for _, certId := range certIds {
|
||||||
|
certRefs = append(certRefs, &sslconfigs.SSLCertRef{
|
||||||
|
IsOn: true,
|
||||||
|
CertId: certId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
certRefsJSON, err := json.Marshal(certRefs)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建策略
|
||||||
|
if len(certIds) > 0 {
|
||||||
|
sslPolicyCreateResp, err := this.RPC().SSLPolicyRPC().CreateSSLPolicy(this.AdminContext(), &pb.CreateSSLPolicyRequest{
|
||||||
|
CertsJSON: certRefsJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sslPolicyId := sslPolicyCreateResp.SslPolicyId
|
||||||
|
httpsConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
|
||||||
|
IsOn: true,
|
||||||
|
SSLPolicyId: sslPolicyId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 访问地址
|
||||||
|
accessAddrs := []*serverconfigs.NetworkAddressConfig{}
|
||||||
|
err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(accessAddrs) == 0 {
|
||||||
|
this.Fail("请添加至少一个外部访问地址")
|
||||||
|
}
|
||||||
|
|
||||||
|
httpJSON, err := json.Marshal(httpConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpsJSON, err := json.Marshal(httpsConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = this.RPC().APINodeRPC().CreateAPINode(this.AdminContext(), &pb.CreateAPINodeRequest{
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
Description: params.Description,
|
Description: params.Description,
|
||||||
Host: params.Host,
|
HttpJSON: httpJSON,
|
||||||
Port: int32(params.Port),
|
HttpsJSON: httpsJSON,
|
||||||
|
AccessAddrsJSON: params.AccessAddrsJSON,
|
||||||
|
IsOn: params.IsOn,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
44
internal/web/actions/default/api/node/createAddrPopup.go
Normal file
44
internal/web/actions/default/api/node/createAddrPopup.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 添加地址
|
||||||
|
type CreateAddrPopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateAddrPopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateAddrPopupAction) RunGet(params struct {
|
||||||
|
}) {
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateAddrPopupAction) RunPost(params struct {
|
||||||
|
Protocol string
|
||||||
|
Addr string
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
params.Must.
|
||||||
|
Field("addr", params.Addr).
|
||||||
|
Require("请输入访问地址")
|
||||||
|
host, port, err := net.SplitHostPort(params.Addr)
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("addr", "错误的访问地址")
|
||||||
|
}
|
||||||
|
|
||||||
|
addrConfig := &serverconfigs.NetworkAddressConfig{
|
||||||
|
Protocol: serverconfigs.Protocol(params.Protocol),
|
||||||
|
Host: host,
|
||||||
|
PortRange: port,
|
||||||
|
}
|
||||||
|
this.Data["addr"] = addrConfig
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -2,8 +2,8 @@ package node
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"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/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"
|
||||||
@@ -48,8 +48,12 @@ func (this *Helper) BeforeAction(action *actions.ActionObject) (goNext bool) {
|
|||||||
// 顶部Tab栏
|
// 顶部Tab栏
|
||||||
selectedTabbar, _ := action.Data["mainTab"]
|
selectedTabbar, _ := action.Data["mainTab"]
|
||||||
tabbar := actionutils.NewTabbar()
|
tabbar := actionutils.NewTabbar()
|
||||||
tabbar.Add("当前节点:"+node.Name, "", "/api", "left long alternate arrow", false)
|
tabbar.Add("节点列表", "", "/api", "", false)
|
||||||
tabbar.Add("设置", "", "/api/node/settings?nodeId="+nodeIdString, "setting", selectedTabbar == "setting")
|
tabbar.Add("设置", "", "/api/node/settings?nodeId="+nodeIdString, "setting", selectedTabbar == "setting")
|
||||||
|
{
|
||||||
|
m := tabbar.Add("当前节点:"+node.Name, "", "", "", false)
|
||||||
|
m["right"] = true
|
||||||
|
}
|
||||||
actionutils.SetTabbar(action, tabbar)
|
actionutils.SetTabbar(action, tabbar)
|
||||||
|
|
||||||
// 左侧菜单栏
|
// 左侧菜单栏
|
||||||
|
|||||||
@@ -9,12 +9,17 @@ func init() {
|
|||||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
server.
|
server.
|
||||||
Helper(helpers.NewUserMustAuth()).
|
Helper(helpers.NewUserMustAuth()).
|
||||||
Helper(NewHelper()).
|
|
||||||
Prefix("/api/node").
|
Prefix("/api/node").
|
||||||
|
|
||||||
|
// 这里不受Helper的约束
|
||||||
|
GetPost("/createAddrPopup", new(CreateAddrPopupAction)).
|
||||||
|
GetPost("/updateAddrPopup", new(UpdateAddrPopupAction)).
|
||||||
|
|
||||||
// 节点相关
|
// 节点相关
|
||||||
|
Helper(NewHelper()).
|
||||||
GetPost("/settings", new(SettingsAction)).
|
GetPost("/settings", new(SettingsAction)).
|
||||||
|
|
||||||
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
)
|
)
|
||||||
@@ -32,12 +35,69 @@ func (this *SettingsAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||||
|
if len(node.HttpJSON) > 0 {
|
||||||
|
err = json.Unmarshal(node.HttpJSON, httpConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
|
||||||
|
if len(node.HttpsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(node.HttpsJSON, httpsConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听地址
|
||||||
|
listens := []*serverconfigs.NetworkAddressConfig{}
|
||||||
|
listens = append(listens, httpConfig.Listen...)
|
||||||
|
listens = append(listens, httpsConfig.Listen...)
|
||||||
|
|
||||||
|
// 证书信息
|
||||||
|
certs := []*sslconfigs.SSLCertConfig{}
|
||||||
|
sslPolicyId := int64(0)
|
||||||
|
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 {
|
||||||
|
sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sslPolicyConfigJSON := sslPolicyConfigResp.SslPolicyJSON
|
||||||
|
if len(sslPolicyConfigJSON) > 0 {
|
||||||
|
sslPolicyId = httpsConfig.SSLPolicyRef.SSLPolicyId
|
||||||
|
|
||||||
|
sslPolicy := &sslconfigs.SSLPolicy{}
|
||||||
|
err = json.Unmarshal(sslPolicyConfigJSON, sslPolicy)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
certs = sslPolicy.Certs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accessAddrs := []*serverconfigs.NetworkAddressConfig{}
|
||||||
|
if len(node.AccessAddrsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(node.AccessAddrsJSON, &accessAddrs)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
this.Data["node"] = maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
"description": node.Description,
|
"description": node.Description,
|
||||||
"host": node.Host,
|
"isOn": node.IsOn,
|
||||||
"port": node.Port,
|
"listens": listens,
|
||||||
|
"certs": certs,
|
||||||
|
"sslPolicyId": sslPolicyId,
|
||||||
|
"accessAddrs": accessAddrs,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
@@ -47,27 +107,126 @@ func (this *SettingsAction) RunGet(params struct {
|
|||||||
func (this *SettingsAction) RunPost(params struct {
|
func (this *SettingsAction) RunPost(params struct {
|
||||||
NodeId int64
|
NodeId int64
|
||||||
Name string
|
Name string
|
||||||
Host string
|
SslPolicyId int64
|
||||||
Port int
|
ListensJSON []byte
|
||||||
|
CertIdsJSON []byte
|
||||||
|
AccessAddrsJSON []byte
|
||||||
Description string
|
Description string
|
||||||
|
IsOn bool
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("name", params.Name).
|
Field("name", params.Name).
|
||||||
Require("请输入API节点").
|
Require("请输入API节点名称")
|
||||||
Field("host", params.Host).
|
|
||||||
Require("请输入主机地址").
|
|
||||||
Field("port", params.Port).
|
|
||||||
Gt(0, "端口不能小于1").
|
|
||||||
Lte(65535, "端口不能大于65535")
|
|
||||||
|
|
||||||
_, err := this.RPC().APINodeRPC().UpdateAPINode(this.AdminContext(), &pb.UpdateAPINodeRequest{
|
httpConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||||
|
httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
|
||||||
|
|
||||||
|
// 监听地址
|
||||||
|
listens := []*serverconfigs.NetworkAddressConfig{}
|
||||||
|
err := json.Unmarshal(params.ListensJSON, &listens)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(listens) == 0 {
|
||||||
|
this.Fail("请添加至少一个进程监听地址")
|
||||||
|
}
|
||||||
|
for _, addr := range listens {
|
||||||
|
if addr.Protocol.IsHTTPFamily() {
|
||||||
|
httpConfig.IsOn = true
|
||||||
|
httpConfig.Listen = append(httpConfig.Listen, addr)
|
||||||
|
} else if addr.Protocol.IsHTTPSFamily() {
|
||||||
|
httpsConfig.IsOn = true
|
||||||
|
httpsConfig.Listen = append(httpsConfig.Listen, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 证书
|
||||||
|
certIds := []int64{}
|
||||||
|
if len(params.CertIdsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(params.CertIdsJSON, &certIds)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if httpsConfig.IsOn && len(httpsConfig.Listen) > 0 && len(certIds) == 0 {
|
||||||
|
this.Fail("请添加至少一个证书")
|
||||||
|
}
|
||||||
|
|
||||||
|
certRefs := []*sslconfigs.SSLCertRef{}
|
||||||
|
for _, certId := range certIds {
|
||||||
|
certRefs = append(certRefs, &sslconfigs.SSLCertRef{
|
||||||
|
IsOn: true,
|
||||||
|
CertId: certId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
certRefsJSON, err := json.Marshal(certRefs)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建策略
|
||||||
|
sslPolicyId := params.SslPolicyId
|
||||||
|
if sslPolicyId == 0 {
|
||||||
|
if len(certIds) > 0 {
|
||||||
|
sslPolicyCreateResp, err := this.RPC().SSLPolicyRPC().CreateSSLPolicy(this.AdminContext(), &pb.CreateSSLPolicyRequest{
|
||||||
|
CertsJSON: certRefsJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sslPolicyId = sslPolicyCreateResp.SslPolicyId
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err = this.RPC().SSLPolicyRPC().UpdateSSLPolicy(this.AdminContext(), &pb.UpdateSSLPolicyRequest{
|
||||||
|
SslPolicyId: sslPolicyId,
|
||||||
|
CertsJSON: certRefsJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpsConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
|
||||||
|
IsOn: true,
|
||||||
|
SSLPolicyId: sslPolicyId,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 访问地址
|
||||||
|
accessAddrs := []*serverconfigs.NetworkAddressConfig{}
|
||||||
|
err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(accessAddrs) == 0 {
|
||||||
|
this.Fail("请添加至少一个外部访问地址")
|
||||||
|
}
|
||||||
|
|
||||||
|
httpJSON, err := json.Marshal(httpConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpsJSON, err := json.Marshal(httpsConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = this.RPC().APINodeRPC().UpdateAPINode(this.AdminContext(), &pb.UpdateAPINodeRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
Description: params.Description,
|
Description: params.Description,
|
||||||
Host: params.Host,
|
HttpJSON: httpJSON,
|
||||||
Port: int32(params.Port),
|
HttpsJSON: httpsJSON,
|
||||||
|
AccessAddrsJSON: params.AccessAddrsJSON,
|
||||||
|
IsOn: params.IsOn,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
42
internal/web/actions/default/api/node/updateAddrPopup.go
Normal file
42
internal/web/actions/default/api/node/updateAddrPopup.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateAddrPopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAddrPopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAddrPopupAction) RunGet(params struct{}) {
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAddrPopupAction) RunPost(params struct {
|
||||||
|
Protocol string
|
||||||
|
Addr string
|
||||||
|
Must *actions.Must
|
||||||
|
}) {
|
||||||
|
params.Must.
|
||||||
|
Field("addr", params.Addr).
|
||||||
|
Require("请输入访问地址")
|
||||||
|
host, port, err := net.SplitHostPort(params.Addr)
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("addr", "错误的访问地址")
|
||||||
|
}
|
||||||
|
|
||||||
|
addrConfig := &serverconfigs.NetworkAddressConfig{
|
||||||
|
Protocol: serverconfigs.Protocol(params.Protocol),
|
||||||
|
Host: host,
|
||||||
|
PortRange: port,
|
||||||
|
}
|
||||||
|
this.Data["addr"] = addrConfig
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"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/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -76,7 +76,7 @@ func (this *InstallAction) RunGet(params struct {
|
|||||||
apiNodes := apiNodesResp.Nodes
|
apiNodes := apiNodesResp.Nodes
|
||||||
apiEndpoints := []string{}
|
apiEndpoints := []string{}
|
||||||
for _, apiNode := range apiNodes {
|
for _, apiNode := range apiNodes {
|
||||||
apiEndpoints = append(apiEndpoints, apiNode.Address)
|
apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...)
|
||||||
}
|
}
|
||||||
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
||||||
|
|
||||||
|
|||||||
155
internal/web/actions/default/nodes/nodeutils/utils.go
Normal file
155
internal/web/actions/default/nodes/nodeutils/utils.go
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package nodeutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MessageResult struct {
|
||||||
|
NodeId int64 `json:"nodeId"`
|
||||||
|
NodeName string `json:"nodeName"`
|
||||||
|
IsOK bool `json:"isOk"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 向集群发送命令消息
|
||||||
|
func SendMessageToCluster(ctx context.Context, clusterId int64, code string, msg interface{}, timeoutSeconds int32) (results []*MessageResult, err error) {
|
||||||
|
results = []*MessageResult{}
|
||||||
|
|
||||||
|
msgJSON, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
return results, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultRPCClient, err := rpc.SharedRPC()
|
||||||
|
if err != nil {
|
||||||
|
return results, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有节点
|
||||||
|
nodesResp, err := defaultRPCClient.NodeRPC().FindAllEnabledNodesWithClusterId(ctx, &pb.FindAllEnabledNodesWithClusterIdRequest{ClusterId: clusterId})
|
||||||
|
if err != nil {
|
||||||
|
return results, err
|
||||||
|
}
|
||||||
|
nodes := nodesResp.Nodes
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcMap := map[int64]*rpc.RPCClient{} // apiNodeId => RPCClient
|
||||||
|
locker := &sync.Mutex{}
|
||||||
|
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(len(nodes))
|
||||||
|
for _, node := range nodes {
|
||||||
|
if len(node.ConnectedAPINodeIds) == 0 {
|
||||||
|
locker.Lock()
|
||||||
|
results = append(results, &MessageResult{
|
||||||
|
NodeId: node.Id,
|
||||||
|
NodeName: node.Name,
|
||||||
|
IsOK: false,
|
||||||
|
Message: "节点尚未连接到API",
|
||||||
|
})
|
||||||
|
locker.Unlock()
|
||||||
|
wg.Done()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取API节点信息
|
||||||
|
apiNodeId := node.ConnectedAPINodeIds[0]
|
||||||
|
rpcClient, ok := rpcMap[apiNodeId]
|
||||||
|
if !ok {
|
||||||
|
apiNodeResp, err := defaultRPCClient.APINodeRPC().FindEnabledAPINode(ctx, &pb.FindEnabledAPINodeRequest{NodeId: apiNodeId})
|
||||||
|
if err != nil {
|
||||||
|
locker.Lock()
|
||||||
|
results = append(results, &MessageResult{
|
||||||
|
NodeId: node.Id,
|
||||||
|
NodeName: node.Name,
|
||||||
|
IsOK: false,
|
||||||
|
Message: "无法读取对应的API节点信息:" + err.Error(),
|
||||||
|
})
|
||||||
|
locker.Unlock()
|
||||||
|
wg.Done()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiNodeResp.Node == nil {
|
||||||
|
locker.Lock()
|
||||||
|
results = append(results, &MessageResult{
|
||||||
|
NodeId: node.Id,
|
||||||
|
NodeName: node.Name,
|
||||||
|
IsOK: false,
|
||||||
|
Message: "无法读取对应的API节点信息:API节点ID:" + strconv.FormatInt(apiNodeId, 10),
|
||||||
|
})
|
||||||
|
locker.Unlock()
|
||||||
|
wg.Done()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
apiNode := apiNodeResp.Node
|
||||||
|
|
||||||
|
apiRPCClient, err := rpc.NewRPCClient(&configs.APIConfig{
|
||||||
|
RPC: struct {
|
||||||
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
}{
|
||||||
|
Endpoints: apiNode.AccessAddrs,
|
||||||
|
},
|
||||||
|
NodeId: apiNode.UniqueId,
|
||||||
|
Secret: apiNode.Secret,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
locker.Lock()
|
||||||
|
results = append(results, &MessageResult{
|
||||||
|
NodeId: node.Id,
|
||||||
|
NodeName: node.Name,
|
||||||
|
IsOK: false,
|
||||||
|
Message: "初始化API节点错误:API节点ID:" + strconv.FormatInt(apiNodeId, 10) + ":" + err.Error(),
|
||||||
|
})
|
||||||
|
locker.Unlock()
|
||||||
|
wg.Done()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rpcMap[apiNodeId] = apiRPCClient
|
||||||
|
rpcClient = apiRPCClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送消息
|
||||||
|
go func(node *pb.Node) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
result, err := rpcClient.NodeRPC().SendCommandToNode(ctx, &pb.NodeStreamMessage{
|
||||||
|
NodeId: node.Id,
|
||||||
|
TimeoutSeconds: timeoutSeconds,
|
||||||
|
Code: code,
|
||||||
|
DataJSON: msgJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
locker.Lock()
|
||||||
|
results = append(results, &MessageResult{
|
||||||
|
NodeId: node.Id,
|
||||||
|
NodeName: node.Name,
|
||||||
|
IsOK: false,
|
||||||
|
Message: "API返回错误:" + err.Error(),
|
||||||
|
})
|
||||||
|
locker.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
locker.Lock()
|
||||||
|
results = append(results, &MessageResult{
|
||||||
|
NodeId: node.Id,
|
||||||
|
NodeName: node.Name,
|
||||||
|
IsOK: result.IsOk,
|
||||||
|
Message: result.Message,
|
||||||
|
})
|
||||||
|
locker.Unlock()
|
||||||
|
}(node)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
22
internal/web/actions/default/nodes/nodeutils/utils_test.go
Normal file
22
internal/web/actions/default/nodes/nodeutils/utils_test.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package nodeutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSendMessageToCluster(t *testing.T) {
|
||||||
|
rpcClient, err := rpc.SharedRPC()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx := rpcClient.Context(1)
|
||||||
|
|
||||||
|
results, err := SendMessageToCluster(ctx, 1, "test", nil, 30)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
logs.PrintAsJSON(results, t)
|
||||||
|
}
|
||||||
38
internal/web/actions/default/servers/components/cache/cacheutils/utils.go
vendored
Normal file
38
internal/web/actions/default/servers/components/cache/cacheutils/utils.go
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package cacheutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 查找缓存策略名称并忽略错误
|
||||||
|
func FindCachePolicyNameWithoutError(parent *actionutils.ParentAction, cachePolicyId int64) string {
|
||||||
|
policy, err := FindCachePolicy(parent, cachePolicyId)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if policy == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return policy.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找缓存策略配置
|
||||||
|
func FindCachePolicy(parent *actionutils.ParentAction, cachePolicyId int64) (*serverconfigs.HTTPCachePolicy, error) {
|
||||||
|
resp, err := parent.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(parent.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{CachePolicyId: cachePolicyId})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(resp.CachePolicyJSON) == 0 {
|
||||||
|
return nil, errors.New("cache policy not found")
|
||||||
|
}
|
||||||
|
config := &serverconfigs.HTTPCachePolicy{}
|
||||||
|
err = json.Unmarshal(resp.CachePolicyJSON, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ type CleanAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *CleanAction) Init() {
|
func (this *CleanAction) Init() {
|
||||||
this.Nav("", "", "")
|
this.Nav("", "", "clean")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *CleanAction) RunGet(params struct{}) {
|
func (this *CleanAction) RunGet(params struct{}) {
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Helper struct {
|
type Helper struct {
|
||||||
@@ -12,11 +15,23 @@ func NewHelper() *Helper {
|
|||||||
return &Helper{}
|
return &Helper{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Helper) BeforeAction(action *actions.ActionObject) {
|
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) {
|
||||||
|
action := actionPtr.Object()
|
||||||
if action.Request.Method != http.MethodGet {
|
if action.Request.Method != http.MethodGet {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
action.Data["mainTab"] = "component"
|
action.Data["mainTab"] = "component"
|
||||||
action.Data["secondMenuItem"] = "cache"
|
action.Data["secondMenuItem"] = "cache"
|
||||||
|
|
||||||
|
cachePolicyId := action.ParamInt64("cachePolicyId")
|
||||||
|
action.Data["cachePolicyId"] = cachePolicyId
|
||||||
|
|
||||||
|
parentActionValue := reflect.ValueOf(actionPtr).Elem().FieldByName("ParentAction")
|
||||||
|
if parentActionValue.IsValid() {
|
||||||
|
parentAction, isOk := parentActionValue.Interface().(actionutils.ParentAction)
|
||||||
|
if isOk {
|
||||||
|
action.Data["cachePolicyName"] = cacheutils.FindCachePolicyNameWithoutError(&parentAction, cachePolicyId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,15 @@ func init() {
|
|||||||
Get("", new(IndexAction)).
|
Get("", new(IndexAction)).
|
||||||
GetPost("/createPopup", new(CreatePopupAction)).
|
GetPost("/createPopup", new(CreatePopupAction)).
|
||||||
Get("/policy", new(PolicyAction)).
|
Get("/policy", new(PolicyAction)).
|
||||||
GetPost("/updatePopup", new(UpdatePopupAction)).
|
GetPost("/update", new(UpdateAction)).
|
||||||
GetPost("/clean", new(CleanAction)).
|
GetPost("/clean", new(CleanAction)).
|
||||||
GetPost("/preheat", new(PreheatAction)).
|
GetPost("/preheat", new(PreheatAction)).
|
||||||
GetPost("/purge", new(PurgeAction)).
|
GetPost("/purge", new(PurgeAction)).
|
||||||
GetPost("/stat", new(StatAction)).
|
GetPost("/stat", new(StatAction)).
|
||||||
GetPost("/test", new(TestAction)).
|
GetPost("/test", new(TestAction)).
|
||||||
Post("/delete", new(DeleteAction)).
|
Post("/delete", new(DeleteAction)).
|
||||||
|
Post("/testRead", new(TestReadAction)).
|
||||||
|
Post("/testWrite", new(TestWriteAction)).
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,30 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
)
|
||||||
|
|
||||||
type PolicyAction struct {
|
type PolicyAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PolicyAction) Init() {
|
func (this *PolicyAction) Init() {
|
||||||
this.Nav("", "", "")
|
this.Nav("", "", "index")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PolicyAction) RunGet(params struct{}) {
|
func (this *PolicyAction) RunGet(params struct {
|
||||||
|
CachePolicyId int64
|
||||||
|
}) {
|
||||||
|
cachePolicy, err := cacheutils.FindCachePolicy(this.Parent(), params.CachePolicyId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["cachePolicy"] = cachePolicy
|
||||||
|
|
||||||
|
this.Data["typeName"] = serverconfigs.FindCachePolicyTypeName(cachePolicy.Type)
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ type PreheatAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *PreheatAction) Init() {
|
func (this *PreheatAction) Init() {
|
||||||
this.Nav("", "", "")
|
this.Nav("", "", "preheat")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PreheatAction) RunGet(params struct{}) {
|
func (this *PreheatAction) RunGet(params struct{}) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ type PurgeAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *PurgeAction) Init() {
|
func (this *PurgeAction) Init() {
|
||||||
this.Nav("", "", "")
|
this.Nav("", "", "purge")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PurgeAction) RunGet(params struct{}) {
|
func (this *PurgeAction) RunGet(params struct{}) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ type StatAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *StatAction) Init() {
|
func (this *StatAction) Init() {
|
||||||
this.Nav("", "", "")
|
this.Nav("", "", "stat")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *StatAction) RunGet(params struct{}) {
|
func (this *StatAction) RunGet(params struct{}) {
|
||||||
|
|||||||
@@ -1,15 +1,34 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
type TestAction struct {
|
type TestAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *TestAction) Init() {
|
func (this *TestAction) Init() {
|
||||||
this.Nav("", "", "")
|
this.Nav("", "", "test")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *TestAction) RunGet(params struct{}) {
|
func (this *TestAction) RunGet(params struct{}) {
|
||||||
|
// 集群列表
|
||||||
|
clustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClusters(this.AdminContext(), &pb.FindAllEnabledNodeClustersRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
clusterMaps := []maps.Map{}
|
||||||
|
for _, cluster := range clustersResp.Clusters {
|
||||||
|
clusterMaps = append(clusterMaps, maps.Map{
|
||||||
|
"id": cluster.Id,
|
||||||
|
"name": cluster.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["clusters"] = clusterMaps
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
52
internal/web/actions/default/servers/components/cache/testRead.go
vendored
Normal file
52
internal/web/actions/default/servers/components/cache/testRead.go
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestReadAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TestReadAction) RunPost(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
CachePolicyId int64
|
||||||
|
Key string
|
||||||
|
}) {
|
||||||
|
cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{CachePolicyId: params.CachePolicyId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cachePolicyJSON := cachePolicyResp.CachePolicyJSON
|
||||||
|
if len(cachePolicyJSON) == 0 {
|
||||||
|
this.Fail("找不到要操作的缓存策略")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送命令
|
||||||
|
msg := &messageconfigs.ReadCacheMessage{
|
||||||
|
CachePolicyJSON: cachePolicyJSON,
|
||||||
|
Key: params.Key,
|
||||||
|
}
|
||||||
|
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeReadCache, msg, 10)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isAllOk := true
|
||||||
|
for _, result := range results {
|
||||||
|
if !result.IsOK {
|
||||||
|
isAllOk = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["isAllOk"] = isAllOk
|
||||||
|
this.Data["results"] = results
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
55
internal/web/actions/default/servers/components/cache/testWrite.go
vendored
Normal file
55
internal/web/actions/default/servers/components/cache/testWrite.go
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestWriteAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TestWriteAction) RunPost(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
CachePolicyId int64
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}) {
|
||||||
|
cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{CachePolicyId: params.CachePolicyId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cachePolicyJSON := cachePolicyResp.CachePolicyJSON
|
||||||
|
if len(cachePolicyJSON) == 0 {
|
||||||
|
this.Fail("找不到要操作的缓存策略")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送命令
|
||||||
|
msg := &messageconfigs.WriteCacheMessage{
|
||||||
|
CachePolicyJSON: cachePolicyJSON,
|
||||||
|
Key: params.Key,
|
||||||
|
Value: []byte(params.Value),
|
||||||
|
LifeSeconds: 3600,
|
||||||
|
}
|
||||||
|
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeWriteCache, msg, 10)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isAllOk := true
|
||||||
|
for _, result := range results {
|
||||||
|
if !result.IsOK {
|
||||||
|
isAllOk = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["isAllOk"] = isAllOk
|
||||||
|
this.Data["results"] = results
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -8,15 +8,15 @@ import (
|
|||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpdatePopupAction struct {
|
type UpdateAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *UpdatePopupAction) Init() {
|
func (this *UpdateAction) Init() {
|
||||||
this.Nav("", "", "")
|
this.Nav("", "", "update")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *UpdatePopupAction) RunGet(params struct {
|
func (this *UpdateAction) RunGet(params struct {
|
||||||
CachePolicyId int64
|
CachePolicyId int64
|
||||||
}) {
|
}) {
|
||||||
configResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{CachePolicyId: params.CachePolicyId})
|
configResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{CachePolicyId: params.CachePolicyId})
|
||||||
@@ -44,7 +44,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
|
|||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *UpdatePopupAction) RunPost(params struct {
|
func (this *UpdateAction) RunPost(params struct {
|
||||||
CachePolicyId int64
|
CachePolicyId int64
|
||||||
|
|
||||||
Name string
|
Name string
|
||||||
@@ -78,7 +78,7 @@ func (this *ServerHelper) createLeftMenu(action *actions.ActionObject) {
|
|||||||
// TABBAR
|
// TABBAR
|
||||||
selectedTabbar, _ := action.Data["mainTab"]
|
selectedTabbar, _ := action.Data["mainTab"]
|
||||||
tabbar := actionutils.NewTabbar()
|
tabbar := actionutils.NewTabbar()
|
||||||
tabbar.Add("服务首页", "", "/servers", "", false)
|
tabbar.Add("服务列表", "", "/servers", "", false)
|
||||||
//tabbar.Add("看板", "", "/servers/server/board?serverId="+serverIdString, "dashboard", selectedTabbar == "board")
|
//tabbar.Add("看板", "", "/servers/server/board?serverId="+serverIdString, "dashboard", selectedTabbar == "board")
|
||||||
tabbar.Add("日志", "", "/servers/server/log?serverId="+serverIdString, "history", selectedTabbar == "log")
|
tabbar.Add("日志", "", "/servers/server/log?serverId="+serverIdString, "history", selectedTabbar == "log")
|
||||||
//tabbar.Add("统计", "", "/servers/server/stat?serverId="+serverIdString, "chart area", selectedTabbar == "stat")
|
//tabbar.Add("统计", "", "/servers/server/stat?serverId="+serverIdString, "chart area", selectedTabbar == "stat")
|
||||||
|
|||||||
56
web/public/js/components/api-node/api-node-addresses-box.js
Normal file
56
web/public/js/components/api-node/api-node-addresses-box.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
Vue.component("api-node-addresses-box", {
|
||||||
|
props: ["v-addrs", "v-name"],
|
||||||
|
data: function () {
|
||||||
|
let addrs = this.vAddrs
|
||||||
|
if (addrs == null) {
|
||||||
|
addrs = []
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
addrs: addrs
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 添加IP地址
|
||||||
|
addAddr: function () {
|
||||||
|
let that = this;
|
||||||
|
teaweb.popup("/api/node/createAddrPopup", {
|
||||||
|
height: "16em",
|
||||||
|
callback: function (resp) {
|
||||||
|
that.addrs.push(resp.data.addr);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改地址
|
||||||
|
updateAddr: function (index, addr) {
|
||||||
|
let that = this;
|
||||||
|
window.UPDATING_ADDR = addr
|
||||||
|
teaweb.popup("/api/node/updateAddrPopup?addressId=", {
|
||||||
|
callback: function (resp) {
|
||||||
|
Vue.set(that.addrs, index, resp.data.addr);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除IP地址
|
||||||
|
removeAddr: function (index) {
|
||||||
|
this.addrs.$remove(index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" :name="vName" :value="JSON.stringify(addrs)"/>
|
||||||
|
<div v-if="addrs.length > 0">
|
||||||
|
<div>
|
||||||
|
<div v-for="(addr, index) in addrs" class="ui label small">
|
||||||
|
{{addr.protocol}}://{{addr.host}}:{{addr.portRange}}</span>
|
||||||
|
<a href="" title="修改" @click.prevent="updateAddr(index, addr)"><i class="icon pencil small"></i></a>
|
||||||
|
<a href="" title="删除" @click.prevent="removeAddr(index)"><i class="icon remove"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="ui button small" type="button" @click.prevent="addAddr()">+</button>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
Vue.component("network-addresses-box", {
|
Vue.component("network-addresses-box", {
|
||||||
props: ["v-server-type", "v-addresses", "v-protocol"],
|
props: ["v-server-type", "v-addresses", "v-protocol", "v-name"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let addresses = this.vAddresses
|
let addresses = this.vAddresses
|
||||||
if (addresses == null) {
|
if (addresses == null) {
|
||||||
@@ -9,9 +9,16 @@ Vue.component("network-addresses-box", {
|
|||||||
if (protocol == null) {
|
if (protocol == null) {
|
||||||
protocol = ""
|
protocol = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let name = this.vName
|
||||||
|
if (name == null) {
|
||||||
|
name = "addresses"
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
addresses: addresses,
|
addresses: addresses,
|
||||||
protocol: protocol
|
protocol: protocol,
|
||||||
|
name: name
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -24,22 +31,28 @@ Vue.component("network-addresses-box", {
|
|||||||
let that = this
|
let that = this
|
||||||
teaweb.popup("/servers/addPortPopup?serverType=" + this.vServerType + "&protocol=" + this.protocol, {
|
teaweb.popup("/servers/addPortPopup?serverType=" + this.vServerType + "&protocol=" + this.protocol, {
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
var addr = resp.data.address;
|
var addr = resp.data.address
|
||||||
that.addresses.push(addr);
|
that.addresses.push(addr)
|
||||||
if (["https", "https4", "https6"].$contains(addr.protocol)) {
|
if (["https", "https4", "https6"].$contains(addr.protocol)) {
|
||||||
this.tlsProtocolName = "HTTPS";
|
this.tlsProtocolName = "HTTPS"
|
||||||
} else if (["tls", "tls4", "tls6"].$contains(addr.protocol)) {
|
} else if (["tls", "tls4", "tls6"].$contains(addr.protocol)) {
|
||||||
this.tlsProtocolName = "TLS";
|
this.tlsProtocolName = "TLS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发送事件
|
||||||
|
that.$emit("change", that.addresses)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
removeAddr: function (index) {
|
removeAddr: function (index) {
|
||||||
this.addresses.$remove(index);
|
this.addresses.$remove(index);
|
||||||
|
|
||||||
|
// 发送事件
|
||||||
|
this.$emit("change", this.addresses)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="addresses" :value="JSON.stringify(addresses)"/>
|
<input type="hidden" :name="name" :value="JSON.stringify(addresses)"/>
|
||||||
<div v-if="addresses.length > 0">
|
<div v-if="addresses.length > 0">
|
||||||
<div class="ui label small" v-for="(addr, index) in addresses">
|
<div class="ui label small" v-for="(addr, index) in addresses">
|
||||||
{{addr.protocol}}://<span v-if="addr.host.length > 0">{{addr.host}}</span><span v-if="addr.host.length == 0">*</span>:{{addr.portRange}}
|
{{addr.protocol}}://<span v-if="addr.host.length > 0">{{addr.host}}</span><span v-if="addr.host.length == 0">*</span>:{{addr.portRange}}
|
||||||
|
|||||||
7
web/public/js/components/common/size-capacity-view.js
Normal file
7
web/public/js/components/common/size-capacity-view.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Vue.component("size-capacity-view", {
|
||||||
|
props:["v-default-text", "v-value"],
|
||||||
|
template: `<div>
|
||||||
|
<span v-if="vValue != null && vValue.count > 0">{{vValue.count}}{{vValue.unit.toUpperCase()}}</span>
|
||||||
|
<span v-else>{{vDefaultText}}</span>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
71
web/public/js/components/server/ssl-certs-box.js
Normal file
71
web/public/js/components/server/ssl-certs-box.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
Vue.component("ssl-certs-box", {
|
||||||
|
props: ["v-certs", "v-protocol"],
|
||||||
|
data: function () {
|
||||||
|
let certs = this.vCerts
|
||||||
|
if (certs == null) {
|
||||||
|
certs = []
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
certs: certs
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
certIds: function () {
|
||||||
|
return this.certs.map(function (v) {
|
||||||
|
return v.id
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 删除证书
|
||||||
|
removeCert: function (index) {
|
||||||
|
let that = this
|
||||||
|
teaweb.confirm("确定删除此证书吗?证书数据仍然保留,只是当前服务不再使用此证书。", function () {
|
||||||
|
that.certs.$remove(index)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 选择证书
|
||||||
|
selectCert: function () {
|
||||||
|
let that = this
|
||||||
|
teaweb.popup("/servers/components/ssl/selectPopup", {
|
||||||
|
width: "50em",
|
||||||
|
height: "30em",
|
||||||
|
callback: function (resp) {
|
||||||
|
that.certs.push(resp.data.cert)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上传证书
|
||||||
|
uploadCert: function () {
|
||||||
|
let that = this
|
||||||
|
teaweb.popup("/servers/components/ssl/uploadPopup", {
|
||||||
|
height: "28em",
|
||||||
|
callback: function (resp) {
|
||||||
|
teaweb.success("上传成功", function () {
|
||||||
|
that.certs.push(resp.data.cert)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 格式化时间
|
||||||
|
formatTime: function (timestamp) {
|
||||||
|
return new Date(timestamp * 1000).format("Y-m-d")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" name="certIdsJSON" :value="JSON.stringify(certIds())"/>
|
||||||
|
<div v-if="certs != null && certs.length > 0">
|
||||||
|
<div class="ui label small" v-for="(cert, index) in certs">
|
||||||
|
{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}} <a href="" title="删除" @click.prevent="removeCert()"><i class="icon remove"></i></a>
|
||||||
|
</div>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<span class="red">选择或上传证书后<span v-if="vProtocol == 'https'">HTTPS</span><span v-if="vProtocol == 'tls'">TLS</span>服务才能生效。</span>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
</div>
|
||||||
|
<button class="ui button tiny" type="button" @click.prevent="selectCert()">选择已有证书</button>
|
||||||
|
<button class="ui button tiny" type="button" @click.prevent="uploadCert()">上传新证书</button>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
@@ -8,15 +8,21 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>节点名称</th>
|
<th>节点名称</th>
|
||||||
<th>主机地址</th>
|
<th>访问地址</th>
|
||||||
<th>端口</th>
|
<th class="two wide">状态</th>
|
||||||
<th class="two op">操作</th>
|
<th class="two op">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr v-for="node in nodes">
|
<tr v-for="node in nodes">
|
||||||
<td>{{node.name}}</td>
|
<td>{{node.name}}</td>
|
||||||
<td>{{node.host}}</td>
|
<td>
|
||||||
<td>{{node.port}}</td>
|
<div v-if="node.accessAddrs != null && node.accessAddrs.length > 0">
|
||||||
|
<span class="ui label tiny" v-for="addr in node.accessAddrs">{{addr}}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<label-on :v-is-on="node.isOn"></label-on>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a :href="'/api/node/settings?nodeId=' + node.id">设置</a>
|
<a :href="'/api/node/settings?nodeId=' + node.id">设置</a>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -10,17 +10,23 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>主机地址 *</td>
|
<td>进程监听端口 *</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="host" maxlength="100"/>
|
<network-addresses-box :v-name="'listensJSON'" :v-server-type="'httpWeb'" @change="changeListens"></network-addresses-box>
|
||||||
<p class="comment">IP地址或者域名。</p>
|
<p class="comment">API节点进程监听的网络端口。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="hasHTTPS">
|
||||||
|
<td>HTTPS证书 *</td>
|
||||||
|
<td>
|
||||||
|
<ssl-certs-box :v-protocol="'https'"></ssl-certs-box>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>端口 *</td>
|
<td>外部访问地址 *</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="port" maxlength="5" style="width:6em"/>
|
<api-node-addresses-box :v-name="'accessAddrsJSON'"></api-node-addresses-box>
|
||||||
<p class="comment">1-65535之间。</p>
|
<p class="comment">外部访问API节点的网络地址。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@@ -34,6 +40,15 @@
|
|||||||
<textarea name="description" maxlength="200" rows="3"></textarea>
|
<textarea name="description" maxlength="200" rows="3"></textarea>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>是否启用</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input type="checkbox" name="isOn" value="1" checked="checked"/>
|
||||||
|
<label></label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<submit-btn></submit-btn>
|
<submit-btn></submit-btn>
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.success = NotifySuccess("保存成功", "/api")
|
this.success = NotifySuccess("保存成功", "/api")
|
||||||
|
|
||||||
|
this.hasHTTPS = false
|
||||||
|
this.changeListens = function (addrs) {
|
||||||
|
this.hasHTTPS = addrs.$any(function (k, v) {
|
||||||
|
return v.protocol == "https"
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
24
web/views/@default/api/node/createAddrPopup.html
Normal file
24
web/views/@default/api/node/createAddrPopup.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
|
<h3>添加访问地址</h3>
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td>网络协议</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" name="protocol">
|
||||||
|
<option value="http">HTTP</option>
|
||||||
|
<option value="https">HTTPS</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="title">访问地址</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="addr" maxlength="100" ref="focus"/>
|
||||||
|
<p class="comment">可以是"IP:端口"或者"域名:端口"。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.success = NotifyPopup
|
this.success = NotifyPopup
|
||||||
|
|
||||||
this.policyType = this.cachePolicy.type
|
|
||||||
})
|
})
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<div class="right-box">
|
<div class="right-box">
|
||||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
<input type="hidden" name="nodeId" :value="node.id"/>
|
<input type="hidden" name="nodeId" :value="node.id"/>
|
||||||
|
<input type="hidden" name="sslPolicyId" :value="node.sslPolicyId"/>
|
||||||
<table class="ui table selectable definition">
|
<table class="ui table selectable definition">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">节点名称 *</td>
|
<td class="title">节点名称 *</td>
|
||||||
@@ -12,17 +13,23 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>主机地址 *</td>
|
<td>进程监听端口 *</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="host" maxlength="100" v-model="node.host"/>
|
<network-addresses-box :v-name="'listensJSON'" :v-server-type="'httpWeb'" :v-addresses="node.listens" @change="changeListens"></network-addresses-box>
|
||||||
<p class="comment">IP地址或者域名。</p>
|
<p class="comment">API节点进程监听的网络端口。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="hasHTTPS">
|
||||||
|
<td>HTTPS证书 *</td>
|
||||||
|
<td>
|
||||||
|
<ssl-certs-box :v-certs="node.certs" :v-protocol="'https'"></ssl-certs-box>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>端口 *</td>
|
<td>外部访问地址 *</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="port" maxlength="5" style="width:6em" v-model="node.port"/>
|
<api-node-addresses-box :v-name="'accessAddrsJSON'" :v-addrs="node.accessAddrs"></api-node-addresses-box>
|
||||||
<p class="comment">1-65535之间。</p>
|
<p class="comment">外部访问API节点的网络地址。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@@ -36,6 +43,15 @@
|
|||||||
<textarea name="description" maxlength="200" rows="3" v-model="node.description"></textarea>
|
<textarea name="description" maxlength="200" rows="3" v-model="node.description"></textarea>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>是否启用</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input type="checkbox" name="isOn" value="1" v-model="node.isOn"/>
|
||||||
|
<label></label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<submit-btn></submit-btn>
|
<submit-btn></submit-btn>
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.success = NotifySuccess("保存成功", "/api/node/settings?nodeId=" + this.node.id)
|
this.success = NotifySuccess("保存成功", "/api/node/settings?nodeId=" + this.node.id)
|
||||||
|
|
||||||
|
this.hasHTTPS = this.node.listens.$any(function (k, v) {
|
||||||
|
return v.protocol == "https"
|
||||||
|
})
|
||||||
|
this.changeListens = function (addrs) {
|
||||||
|
this.hasHTTPS = addrs.$any(function (k, v) {
|
||||||
|
return v.protocol == "https"
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
24
web/views/@default/api/node/updateAddrPopup.html
Normal file
24
web/views/@default/api/node/updateAddrPopup.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
|
<h3>修改访问地址</h3>
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td>网络协议</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" name="protocol" v-model="protocol">
|
||||||
|
<option value="http">HTTP</option>
|
||||||
|
<option value="https">HTTPS</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="title">访问地址</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="addr" maxlength="100" ref="focus" v-model="addr"/>
|
||||||
|
<p class="comment">可以是"IP:端口"或者"域名:端口"。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
6
web/views/@default/api/node/updateAddrPopup.js
Normal file
6
web/views/@default/api/node/updateAddrPopup.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.success = NotifyPopup
|
||||||
|
let addr = window.parent.UPDATING_ADDR
|
||||||
|
this.protocol = addr.protocol
|
||||||
|
this.addr = addr.host + ":" + addr.portRange
|
||||||
|
})
|
||||||
11
web/views/@default/servers/components/cache/@policy_menu.html
vendored
Normal file
11
web/views/@default/servers/components/cache/@policy_menu.html
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<second-menu>
|
||||||
|
<menu-item href="/servers/components/cache">列表</menu-item>
|
||||||
|
<span class="item">|</span>
|
||||||
|
<menu-item :href="'/servers/components/cache/policy?cachePolicyId=' + cachePolicyId" code="index">{{cachePolicyName}}</menu-item>
|
||||||
|
<menu-item :href="'/servers/components/cache/test?cachePolicyId=' + cachePolicyId" code="test">测试</menu-item>
|
||||||
|
<menu-item :href="'/servers/components/cache/stat?cachePolicyId=' + cachePolicyId" code="stat">统计</menu-item>
|
||||||
|
<menu-item :href="'/servers/components/cache/clean?cachePolicyId=' + cachePolicyId" code="clean">清理</menu-item>
|
||||||
|
<menu-item :href="'/servers/components/cache/purge?cachePolicyId=' + cachePolicyId" code="purge">删除</menu-item>
|
||||||
|
<menu-item :href="'/servers/components/cache/preheat?cachePolicyId=' + cachePolicyId" code="preheat">预热</menu-item>
|
||||||
|
<menu-item :href="'/servers/components/cache/update?cachePolicyId=' + cachePolicyId" code="update">修改</menu-item>
|
||||||
|
</second-menu>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<td><input type="text" name="name" maxlength="100" ref="focus"/> </td>
|
<td><input type="text" name="name" maxlength="100" ref="focus"/> </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>缓存类型 *</td>
|
<td class="color-border">缓存类型 *</td>
|
||||||
<td>
|
<td>
|
||||||
<select class="ui dropdown auto-width" name="type" v-model="policyType">
|
<select class="ui dropdown auto-width" name="type" v-model="policyType">
|
||||||
<option v-for="type in types" :value="type.type">{{type.name}}</option>
|
<option v-for="type in types" :value="type.type">{{type.name}}</option>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<!-- 文件缓存选项 -->
|
<!-- 文件缓存选项 -->
|
||||||
<tbody v-if="policyType == 'file'">
|
<tbody v-if="policyType == 'file'">
|
||||||
<tr>
|
<tr>
|
||||||
<td>缓存目录 *</td>
|
<td class="color-border">缓存目录 *</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="fileDir" maxlength="500"/>
|
<input type="text" name="fileDir" maxlength="500"/>
|
||||||
<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
|
<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<th>容量</th>
|
<th>容量</th>
|
||||||
<th>引用服务</th>
|
<th>引用服务</th>
|
||||||
<th>状态</th>
|
<th>状态</th>
|
||||||
<th class="three op">操作</th>
|
<th class="two op">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr v-for="(policy, index) in cachePolicies">
|
<tr v-for="(policy, index) in cachePolicies">
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
<td>{{infos[index].countServers}}</td>
|
<td>{{infos[index].countServers}}</td>
|
||||||
<td><label-on :v-is-on="policy.isOn"></label-on></td>
|
<td><label-on :v-is-on="policy.isOn"></label-on></td>
|
||||||
<td>
|
<td>
|
||||||
<a :href="'/servers/components/cache/policy?cachePolicyId=' + policy.id">详情</a> <a href="" @click.prevent="updatePolicy(policy.id)">修改</a> <a href="" @click.prevent="deletePolicy(policy.id)">删除</a>
|
<a :href="'/servers/components/cache/policy?cachePolicyId=' + policy.id">详情</a> <a href="" @click.prevent="deletePolicy(policy.id)">删除</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -11,18 +11,6 @@ Tea.context(function () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改策略
|
|
||||||
this.updatePolicy = function (policyId) {
|
|
||||||
teaweb.popup("/servers/components/cache/updatePopup?cachePolicyId=" + policyId, {
|
|
||||||
height: "27em",
|
|
||||||
callback: function () {
|
|
||||||
teaweb.success("保存成功", function () {
|
|
||||||
window.location.reload()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除策略
|
// 删除策略
|
||||||
this.deletePolicy = function (policyId) {
|
this.deletePolicy = function (policyId) {
|
||||||
let that = this
|
let that = this
|
||||||
|
|||||||
69
web/views/@default/servers/components/cache/policy.html
vendored
Normal file
69
web/views/@default/servers/components/cache/policy.html
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "/left_menu"}
|
||||||
|
|
||||||
|
<div class="right-box">
|
||||||
|
{$template "policy_menu"}
|
||||||
|
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">策略名称</td>
|
||||||
|
<td>{{cachePolicy.name}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>状态</td>
|
||||||
|
<td><label-on :v-is-on="cachePolicy.isOn"></label-on></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="color-border">缓存类型</td>
|
||||||
|
<td>
|
||||||
|
{{typeName}}<span class="small">({{cachePolicy.type}})</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- 文件缓存选项 -->
|
||||||
|
<tbody v-if="cachePolicy.type == 'file'">
|
||||||
|
<tr>
|
||||||
|
<td class="color-border">缓存目录</td>
|
||||||
|
<td>
|
||||||
|
{{cachePolicy.options.dir}}
|
||||||
|
<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>缓存最大容量</td>
|
||||||
|
<td>
|
||||||
|
<size-capacity-view :v-value="cachePolicy.capacity" :v-default-text="'不限'"></size-capacity-view>
|
||||||
|
<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||||
|
</tr>
|
||||||
|
<tbody v-show="moreOptionsVisible">
|
||||||
|
<tr>
|
||||||
|
<td>最大内容长度</td>
|
||||||
|
<td>
|
||||||
|
<size-capacity-view :v-value="cachePolicy.maxSize" :v-default-text="'不限'"></size-capacity-view>
|
||||||
|
<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>容纳Key数量</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="cachePolicy.maxKeys > 0">{{cachePolicy.maxKeys}}</span>
|
||||||
|
<span v-else>不限</span>
|
||||||
|
<p class="comment">可以容纳多少数量的Key,0表示不限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>描述</td>
|
||||||
|
<td>
|
||||||
|
{{cachePolicy.description}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
73
web/views/@default/servers/components/cache/test.html
vendored
Normal file
73
web/views/@default/servers/components/cache/test.html
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "/left_menu"}
|
||||||
|
|
||||||
|
<div class="right-box">
|
||||||
|
{$template "policy_menu"}
|
||||||
|
|
||||||
|
<h3>选择集群</h3>
|
||||||
|
<select class="ui dropdown auto-width" v-model="clusterId">
|
||||||
|
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
|
<h3>测试写入</h3>
|
||||||
|
<form class="ui form" data-tea-action=".testWrite" data-tea-before="beforeWrite" data-tea-done="doneWrite" data-tea-success="successWrite" data-tea-fail="failWrite">
|
||||||
|
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||||
|
<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
|
||||||
|
<table class="ui table selectable definition">
|
||||||
|
<tr>
|
||||||
|
<td class="title">Key</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="key" value="my-key"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Value</td>
|
||||||
|
<td>
|
||||||
|
<textarea name="value" rows="3">my-value</textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>操作结果</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="isRequestingWrite">数据发送中...</div>
|
||||||
|
<span class="red" v-if="!isRequestingWrite && !writeOk && writeMessage.length > 0">失败:{{writeMessage}}</span>
|
||||||
|
<div v-if="!isRequestingWrite && writeOk">
|
||||||
|
<span v-if="writeResults.length == 0" class="red">此集群下没有任何可用的节点。</span>
|
||||||
|
<div class="ui label tiny" v-for="result in writeResults" :class="{green:result.isOk, red:!result.isOk}" style="margin-bottom:0.5em">节点{{result.nodeName}}:{{result.message}}</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn v-if="!isRequestingWrite">提交</submit-btn>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
|
<h3>测试读取</h3>
|
||||||
|
<form class="ui form" data-tea-action=".testRead" data-tea-before="beforeRead" data-tea-done="doneRead" data-tea-success="successRead" data-tea-fail="failRead">
|
||||||
|
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||||
|
<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
|
||||||
|
<table class="ui table selectable definition">
|
||||||
|
<tr>
|
||||||
|
<td class="title">Key</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="key" value="my-key"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>操作结果</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="isRequestingRead">数据发送中...</div>
|
||||||
|
<span class="red" v-if="!isRequestingRead && !readOk && readMessage.length > 0">失败:{{readMessage}}</span>
|
||||||
|
<div v-if="!isRequestingRead && readOk">
|
||||||
|
<span v-if="readResults.length == 0" class="red">此集群下没有任何可用的节点。</span>
|
||||||
|
<div class="ui label tiny" v-for="result in readResults" :class="{green:result.isOk, red:!result.isOk}" style="margin-bottom: 0.5em">节点{{result.nodeName}}:{{result.message}}</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn v-if="!isRequestingRead">提交</submit-btn>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
63
web/views/@default/servers/components/cache/test.js
vendored
Normal file
63
web/views/@default/servers/components/cache/test.js
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
if (this.clusters.length > 0) {
|
||||||
|
this.clusterId = this.clusters[0].id
|
||||||
|
} else {
|
||||||
|
this.clusterId = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isRequestingWrite = false
|
||||||
|
this.writeOk = false
|
||||||
|
this.writeMessage = ""
|
||||||
|
this.writeIsAllOk = false
|
||||||
|
this.writeResults = []
|
||||||
|
|
||||||
|
this.beforeWrite = function () {
|
||||||
|
this.isRequestingWrite = true
|
||||||
|
this.writeOk = false
|
||||||
|
this.writeMessage = ""
|
||||||
|
this.writeResult = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.failWrite = function (resp) {
|
||||||
|
this.writeOk = false
|
||||||
|
this.writeMessage = resp.message
|
||||||
|
}
|
||||||
|
|
||||||
|
this.successWrite = function (resp) {
|
||||||
|
this.writeOk = true
|
||||||
|
this.writeIsAllOk = resp.data.isAllOk
|
||||||
|
this.writeResults = resp.data.results
|
||||||
|
}
|
||||||
|
|
||||||
|
this.doneWrite = function () {
|
||||||
|
this.isRequestingWrite = false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isRequestingRead = false
|
||||||
|
this.readOk = false
|
||||||
|
this.readMessage = ""
|
||||||
|
this.readIsAllOk = false
|
||||||
|
this.readResults = []
|
||||||
|
|
||||||
|
this.beforeRead = function () {
|
||||||
|
this.isRequestingRead = true
|
||||||
|
this.readOk = false
|
||||||
|
this.readMessage = ""
|
||||||
|
this.readResult = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.failRead = function (resp) {
|
||||||
|
this.readOk = false
|
||||||
|
this.readMessage = resp.message
|
||||||
|
};
|
||||||
|
|
||||||
|
this.successRead = function (resp) {
|
||||||
|
this.readOk = true;
|
||||||
|
this.readIsAllOk = resp.data.isAllOk
|
||||||
|
this.readResults = resp.data.results
|
||||||
|
}
|
||||||
|
|
||||||
|
this.doneRead = function () {
|
||||||
|
this.isRequestingRead = false
|
||||||
|
}
|
||||||
|
});
|
||||||
79
web/views/@default/servers/components/cache/update.html
vendored
Normal file
79
web/views/@default/servers/components/cache/update.html
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "/left_menu"}
|
||||||
|
|
||||||
|
<div class="right-box">
|
||||||
|
{$template "policy_menu"}
|
||||||
|
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<input type="hidden" name="cachePolicyId" :value="cachePolicy.id"/>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">策略名称 *</td>
|
||||||
|
<td><input type="text" name="name" maxlength="100" ref="focus" v-model="cachePolicy.name"/> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="color-border">缓存类型 *</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" name="type" v-model="policyType">
|
||||||
|
<option v-for="type in types" :value="type.type">{{type.name}}</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- 文件缓存选项 -->
|
||||||
|
<tbody v-if="policyType == 'file'">
|
||||||
|
<tr>
|
||||||
|
<td class="color-border">缓存目录 *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="fileDir" maxlength="500" v-model="cachePolicy.options.dir"/>
|
||||||
|
<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>缓存最大容量</td>
|
||||||
|
<td>
|
||||||
|
<size-capacity-box :v-name="'capacityJSON'" :v-value="cachePolicy.capacity" :v-count="0" :v-unit="'gb'"></size-capacity-box>
|
||||||
|
<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||||
|
</tr>
|
||||||
|
<tbody v-show="moreOptionsVisible">
|
||||||
|
<tr>
|
||||||
|
<td>最大内容长度</td>
|
||||||
|
<td>
|
||||||
|
<size-capacity-box :v-value="cachePolicy.maxSize" :v-name="'maxSizeJSON'" :v-count="32" :v-unit="'mb'"></size-capacity-box>
|
||||||
|
<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>容纳Key数量</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="maxKeys" maxlength="10" style="width:10em" v-model="cachePolicy.maxKeys"/>
|
||||||
|
<p class="comment">可以容纳多少数量的Key,0表示不限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>描述</td>
|
||||||
|
<td>
|
||||||
|
<textarea maxlength="200" name="description" rows="3" v-model="cachePolicy.description"></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>是否启用</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input type="checkbox" name="isOn" value="1" v-model="cachePolicy.isOn"/>
|
||||||
|
<label></label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
5
web/views/@default/servers/components/cache/update.js
vendored
Normal file
5
web/views/@default/servers/components/cache/update.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.success = NotifyReloadSuccess("保存成功 ")
|
||||||
|
|
||||||
|
this.policyType = this.cachePolicy.type
|
||||||
|
})
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
{$layout "layout_popup"}
|
|
||||||
|
|
||||||
<h3>修改缓存策略</h3>
|
|
||||||
|
|
||||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
|
||||||
<input type="hidden" name="cachePolicyId" :value="cachePolicy.id"/>
|
|
||||||
<table class="ui table definition selectable">
|
|
||||||
<tr>
|
|
||||||
<td class="title">策略名称 *</td>
|
|
||||||
<td><input type="text" name="name" maxlength="100" ref="focus" v-model="cachePolicy.name"/> </td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>缓存类型 *</td>
|
|
||||||
<td>
|
|
||||||
<select class="ui dropdown auto-width" name="type" v-model="policyType">
|
|
||||||
<option v-for="type in types" :value="type.type">{{type.name}}</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- 文件缓存选项 -->
|
|
||||||
<tbody v-if="policyType == 'file'">
|
|
||||||
<tr>
|
|
||||||
<td>缓存目录 *</td>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="fileDir" maxlength="500" v-model="cachePolicy.options.dir"/>
|
|
||||||
<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>缓存最大容量</td>
|
|
||||||
<td>
|
|
||||||
<size-capacity-box :v-name="'capacityJSON'" :v-value="cachePolicy.capacity" :v-count="0" :v-unit="'gb'"></size-capacity-box>
|
|
||||||
<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
|
||||||
</tr>
|
|
||||||
<tbody v-show="moreOptionsVisible">
|
|
||||||
<tr>
|
|
||||||
<td>最大内容长度</td>
|
|
||||||
<td>
|
|
||||||
<size-capacity-box :v-value="cachePolicy.maxSize" :v-name="'maxSizeJSON'" :v-count="32" :v-unit="'mb'"></size-capacity-box>
|
|
||||||
<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>容纳Key数量</td>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="maxKeys" maxlength="10" style="width:10em" v-model="cachePolicy.maxKeys"/>
|
|
||||||
<p class="comment">可以容纳多少数量的Key,0表示不限制。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>描述</td>
|
|
||||||
<td>
|
|
||||||
<textarea maxlength="200" name="description" rows="3" v-model="cachePolicy.description"></textarea>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>是否启用</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui checkbox">
|
|
||||||
<input type="checkbox" name="isOn" value="1" v-model="cachePolicy.isOn"/>
|
|
||||||
<label></label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<submit-btn></submit-btn>
|
|
||||||
</form>
|
|
||||||
Reference in New Issue
Block a user