diff --git a/build/configs/api.template.yaml b/build/configs/api.template.yaml index a5f96fd8..733fcd04 100644 --- a/build/configs/api.template.yaml +++ b/build/configs/api.template.yaml @@ -1,4 +1,4 @@ rpc: - endpoints: [ "127.0.0.1:8003" ] + endpoints: [ "http://127.0.0.1:8003" ] nodeId: "" secret: "" \ No newline at end of file diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go index 468b9122..5d3561a1 100644 --- a/internal/rpc/rpc_client.go +++ b/internal/rpc/rpc_client.go @@ -13,6 +13,7 @@ import ( "github.com/iwind/TeaGo/rands" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "net/url" "time" ) @@ -30,7 +31,19 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { conns := []*grpc.ClientConn{} 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 { return nil, err } diff --git a/internal/rpc/rpc_client_test.go b/internal/rpc/rpc_client_test.go index 243a96c8..8769f966 100644 --- a/internal/rpc/rpc_client_test.go +++ b/internal/rpc/rpc_client_test.go @@ -1,8 +1,8 @@ package rpc import ( - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeAdmin/internal/configs" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" _ "github.com/iwind/TeaGo/bootstrap" stringutil "github.com/iwind/TeaGo/utils/string" "testing" @@ -31,3 +31,66 @@ func TestRPCClient_NodeRPC(t *testing.T) { } 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) +} diff --git a/internal/web/actions/default/api/index.go b/internal/web/actions/default/api/index.go index b6d7d8df..13bf495e 100644 --- a/internal/web/actions/default/api/index.go +++ b/internal/web/actions/default/api/index.go @@ -37,11 +37,10 @@ func (this *IndexAction) RunGet(params struct{}) { for _, node := range nodesResp.Nodes { nodeMaps = append(nodeMaps, maps.Map{ - "id": node.Id, - "isOn": node.IsOn, - "name": node.Name, - "host": node.Host, - "port": node.Port, + "id": node.Id, + "isOn": node.IsOn, + "name": node.Name, + "accessAddrs": node.AccessAddrs, }) } } diff --git a/internal/web/actions/default/api/node/create.go b/internal/web/actions/default/api/node/create.go index 2d70d67c..8810fe34 100644 --- a/internal/web/actions/default/api/node/create.go +++ b/internal/web/actions/default/api/node/create.go @@ -1,8 +1,11 @@ package node import ( - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "encoding/json" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" "github.com/iwind/TeaGo/actions" ) @@ -19,27 +22,113 @@ func (this *CreateAction) RunGet(params struct{}) { } func (this *CreateAction) RunPost(params struct { - Name string - Host string - Port int - Description string + Name string + Description string + ListensJSON []byte + CertIdsJSON []byte + AccessAddrsJSON []byte + IsOn bool Must *actions.Must }) { params.Must. Field("name", params.Name). - Require("请输入API节点"). - Field("host", params.Host). - Require("请输入主机地址"). - Field("port", params.Port). - Gt(0, "端口不能小于1"). - Lte(65535, "端口不能大于65535") + Require("请输入API节点名称") - _, err := this.RPC().APINodeRPC().CreateAPINode(this.AdminContext(), &pb.CreateAPINodeRequest{ - Name: params.Name, - Description: params.Description, - Host: params.Host, - Port: int32(params.Port), + 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, + Description: params.Description, + HttpJSON: httpJSON, + HttpsJSON: httpsJSON, + AccessAddrsJSON: params.AccessAddrsJSON, + IsOn: params.IsOn, }) if err != nil { this.ErrorPage(err) diff --git a/internal/web/actions/default/api/node/createAddrPopup.go b/internal/web/actions/default/api/node/createAddrPopup.go new file mode 100644 index 00000000..69d53d3d --- /dev/null +++ b/internal/web/actions/default/api/node/createAddrPopup.go @@ -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() +} diff --git a/internal/web/actions/default/api/node/helper.go b/internal/web/actions/default/api/node/helper.go index db7f64c9..90434629 100644 --- a/internal/web/actions/default/api/node/helper.go +++ b/internal/web/actions/default/api/node/helper.go @@ -2,8 +2,8 @@ package node import ( "github.com/TeaOSLab/EdgeAdmin/internal/rpc" - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/maps" @@ -48,8 +48,12 @@ func (this *Helper) BeforeAction(action *actions.ActionObject) (goNext bool) { // 顶部Tab栏 selectedTabbar, _ := action.Data["mainTab"] 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") + { + m := tabbar.Add("当前节点:"+node.Name, "", "", "", false) + m["right"] = true + } actionutils.SetTabbar(action, tabbar) // 左侧菜单栏 diff --git a/internal/web/actions/default/api/node/init.go b/internal/web/actions/default/api/node/init.go index 87a602bc..25ac7b12 100644 --- a/internal/web/actions/default/api/node/init.go +++ b/internal/web/actions/default/api/node/init.go @@ -9,12 +9,17 @@ func init() { TeaGo.BeforeStart(func(server *TeaGo.Server) { server. Helper(helpers.NewUserMustAuth()). - Helper(NewHelper()). Prefix("/api/node"). + // 这里不受Helper的约束 + GetPost("/createAddrPopup", new(CreateAddrPopupAction)). + GetPost("/updateAddrPopup", new(UpdateAddrPopupAction)). + // 节点相关 + Helper(NewHelper()). GetPost("/settings", new(SettingsAction)). + EndAll() }) } diff --git a/internal/web/actions/default/api/node/settings.go b/internal/web/actions/default/api/node/settings.go index 3951cea8..4b279aff 100644 --- a/internal/web/actions/default/api/node/settings.go +++ b/internal/web/actions/default/api/node/settings.go @@ -1,8 +1,11 @@ package node import ( - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "encoding/json" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" "github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/maps" ) @@ -32,12 +35,69 @@ func (this *SettingsAction) RunGet(params struct { 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{ "id": node.Id, "name": node.Name, "description": node.Description, - "host": node.Host, - "port": node.Port, + "isOn": node.IsOn, + "listens": listens, + "certs": certs, + "sslPolicyId": sslPolicyId, + "accessAddrs": accessAddrs, } this.Show() @@ -45,29 +105,128 @@ func (this *SettingsAction) RunGet(params struct { // 保存基础设置 func (this *SettingsAction) RunPost(params struct { - NodeId int64 - Name string - Host string - Port int - Description string + NodeId int64 + Name string + SslPolicyId int64 + ListensJSON []byte + CertIdsJSON []byte + AccessAddrsJSON []byte + Description string + IsOn bool Must *actions.Must }) { params.Must. Field("name", params.Name). - Require("请输入API节点"). - Field("host", params.Host). - Require("请输入主机地址"). - Field("port", params.Port). - Gt(0, "端口不能小于1"). - Lte(65535, "端口不能大于65535") + Require("请输入API节点名称") - _, err := this.RPC().APINodeRPC().UpdateAPINode(this.AdminContext(), &pb.UpdateAPINodeRequest{ - NodeId: params.NodeId, - Name: params.Name, - Description: params.Description, - Host: params.Host, - Port: int32(params.Port), + 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, + Name: params.Name, + Description: params.Description, + HttpJSON: httpJSON, + HttpsJSON: httpsJSON, + AccessAddrsJSON: params.AccessAddrsJSON, + IsOn: params.IsOn, }) if err != nil { this.ErrorPage(err) diff --git a/internal/web/actions/default/api/node/updateAddrPopup.go b/internal/web/actions/default/api/node/updateAddrPopup.go new file mode 100644 index 00000000..539270f8 --- /dev/null +++ b/internal/web/actions/default/api/node/updateAddrPopup.go @@ -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() +} diff --git a/internal/web/actions/default/clusters/cluster/node/install.go b/internal/web/actions/default/clusters/cluster/node/install.go index 072fc92f..ceee2c38 100644 --- a/internal/web/actions/default/clusters/cluster/node/install.go +++ b/internal/web/actions/default/clusters/cluster/node/install.go @@ -1,8 +1,8 @@ package node import ( - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "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" "strings" @@ -76,7 +76,7 @@ func (this *InstallAction) RunGet(params struct { apiNodes := apiNodesResp.Nodes apiEndpoints := []string{} for _, apiNode := range apiNodes { - apiEndpoints = append(apiEndpoints, apiNode.Address) + apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...) } this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\"" diff --git a/internal/web/actions/default/nodes/nodeutils/utils.go b/internal/web/actions/default/nodes/nodeutils/utils.go new file mode 100644 index 00000000..18838168 --- /dev/null +++ b/internal/web/actions/default/nodes/nodeutils/utils.go @@ -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 +} diff --git a/internal/web/actions/default/nodes/nodeutils/utils_test.go b/internal/web/actions/default/nodes/nodeutils/utils_test.go new file mode 100644 index 00000000..5cbf07b7 --- /dev/null +++ b/internal/web/actions/default/nodes/nodeutils/utils_test.go @@ -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) +} diff --git a/internal/web/actions/default/servers/components/cache/cacheutils/utils.go b/internal/web/actions/default/servers/components/cache/cacheutils/utils.go new file mode 100644 index 00000000..6cdf130d --- /dev/null +++ b/internal/web/actions/default/servers/components/cache/cacheutils/utils.go @@ -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 +} diff --git a/internal/web/actions/default/servers/components/cache/clean.go b/internal/web/actions/default/servers/components/cache/clean.go index 7ced0c35..9e9fbb0e 100644 --- a/internal/web/actions/default/servers/components/cache/clean.go +++ b/internal/web/actions/default/servers/components/cache/clean.go @@ -7,7 +7,7 @@ type CleanAction struct { } func (this *CleanAction) Init() { - this.Nav("", "", "") + this.Nav("", "", "clean") } func (this *CleanAction) RunGet(params struct{}) { diff --git a/internal/web/actions/default/servers/components/cache/helper.go b/internal/web/actions/default/servers/components/cache/helper.go index d8cba657..a451ce91 100644 --- a/internal/web/actions/default/servers/components/cache/helper.go +++ b/internal/web/actions/default/servers/components/cache/helper.go @@ -1,8 +1,11 @@ package cache 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" "net/http" + "reflect" ) type Helper struct { @@ -12,11 +15,23 @@ func NewHelper() *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 { return } action.Data["mainTab"] = "component" 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) + } + } } diff --git a/internal/web/actions/default/servers/components/cache/init.go b/internal/web/actions/default/servers/components/cache/init.go index 042ebf56..0b43a411 100644 --- a/internal/web/actions/default/servers/components/cache/init.go +++ b/internal/web/actions/default/servers/components/cache/init.go @@ -16,13 +16,15 @@ func init() { Get("", new(IndexAction)). GetPost("/createPopup", new(CreatePopupAction)). Get("/policy", new(PolicyAction)). - GetPost("/updatePopup", new(UpdatePopupAction)). + GetPost("/update", new(UpdateAction)). GetPost("/clean", new(CleanAction)). GetPost("/preheat", new(PreheatAction)). GetPost("/purge", new(PurgeAction)). GetPost("/stat", new(StatAction)). GetPost("/test", new(TestAction)). Post("/delete", new(DeleteAction)). + Post("/testRead", new(TestReadAction)). + Post("/testWrite", new(TestWriteAction)). EndAll() }) } diff --git a/internal/web/actions/default/servers/components/cache/policy.go b/internal/web/actions/default/servers/components/cache/policy.go index 3dc4c3ca..b298e044 100644 --- a/internal/web/actions/default/servers/components/cache/policy.go +++ b/internal/web/actions/default/servers/components/cache/policy.go @@ -1,15 +1,30 @@ 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 { actionutils.ParentAction } 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() } diff --git a/internal/web/actions/default/servers/components/cache/preheat.go b/internal/web/actions/default/servers/components/cache/preheat.go index 73123fab..dadf14a7 100644 --- a/internal/web/actions/default/servers/components/cache/preheat.go +++ b/internal/web/actions/default/servers/components/cache/preheat.go @@ -7,7 +7,7 @@ type PreheatAction struct { } func (this *PreheatAction) Init() { - this.Nav("", "", "") + this.Nav("", "", "preheat") } func (this *PreheatAction) RunGet(params struct{}) { diff --git a/internal/web/actions/default/servers/components/cache/purge.go b/internal/web/actions/default/servers/components/cache/purge.go index fe2030a1..245f0336 100644 --- a/internal/web/actions/default/servers/components/cache/purge.go +++ b/internal/web/actions/default/servers/components/cache/purge.go @@ -7,7 +7,7 @@ type PurgeAction struct { } func (this *PurgeAction) Init() { - this.Nav("", "", "") + this.Nav("", "", "purge") } func (this *PurgeAction) RunGet(params struct{}) { diff --git a/internal/web/actions/default/servers/components/cache/stat.go b/internal/web/actions/default/servers/components/cache/stat.go index 4dfacade..3c32ecd3 100644 --- a/internal/web/actions/default/servers/components/cache/stat.go +++ b/internal/web/actions/default/servers/components/cache/stat.go @@ -7,7 +7,7 @@ type StatAction struct { } func (this *StatAction) Init() { - this.Nav("", "", "") + this.Nav("", "", "stat") } func (this *StatAction) RunGet(params struct{}) { diff --git a/internal/web/actions/default/servers/components/cache/test.go b/internal/web/actions/default/servers/components/cache/test.go index aefc1a64..cc2d988d 100644 --- a/internal/web/actions/default/servers/components/cache/test.go +++ b/internal/web/actions/default/servers/components/cache/test.go @@ -1,15 +1,34 @@ 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 { actionutils.ParentAction } func (this *TestAction) Init() { - this.Nav("", "", "") + this.Nav("", "", "test") } 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() } diff --git a/internal/web/actions/default/servers/components/cache/testRead.go b/internal/web/actions/default/servers/components/cache/testRead.go new file mode 100644 index 00000000..92de0947 --- /dev/null +++ b/internal/web/actions/default/servers/components/cache/testRead.go @@ -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() +} diff --git a/internal/web/actions/default/servers/components/cache/testWrite.go b/internal/web/actions/default/servers/components/cache/testWrite.go new file mode 100644 index 00000000..5ac67bac --- /dev/null +++ b/internal/web/actions/default/servers/components/cache/testWrite.go @@ -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() +} diff --git a/internal/web/actions/default/servers/components/cache/updatePopup.go b/internal/web/actions/default/servers/components/cache/update.go similarity index 91% rename from internal/web/actions/default/servers/components/cache/updatePopup.go rename to internal/web/actions/default/servers/components/cache/update.go index 1c7ee465..69e1b966 100644 --- a/internal/web/actions/default/servers/components/cache/updatePopup.go +++ b/internal/web/actions/default/servers/components/cache/update.go @@ -8,15 +8,15 @@ import ( "github.com/iwind/TeaGo/actions" ) -type UpdatePopupAction struct { +type UpdateAction struct { actionutils.ParentAction } -func (this *UpdatePopupAction) Init() { - this.Nav("", "", "") +func (this *UpdateAction) Init() { + this.Nav("", "", "update") } -func (this *UpdatePopupAction) RunGet(params struct { +func (this *UpdateAction) RunGet(params struct { CachePolicyId int64 }) { 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() } -func (this *UpdatePopupAction) RunPost(params struct { +func (this *UpdateAction) RunPost(params struct { CachePolicyId int64 Name string diff --git a/internal/web/actions/default/servers/serverutils/server_helper.go b/internal/web/actions/default/servers/serverutils/server_helper.go index 596bef5a..9096c6b6 100644 --- a/internal/web/actions/default/servers/serverutils/server_helper.go +++ b/internal/web/actions/default/servers/serverutils/server_helper.go @@ -78,7 +78,7 @@ func (this *ServerHelper) createLeftMenu(action *actions.ActionObject) { // TABBAR selectedTabbar, _ := action.Data["mainTab"] 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/log?serverId="+serverIdString, "history", selectedTabbar == "log") //tabbar.Add("统计", "", "/servers/server/stat?serverId="+serverIdString, "chart area", selectedTabbar == "stat") diff --git a/web/public/js/components/api-node/api-node-addresses-box.js b/web/public/js/components/api-node/api-node-addresses-box.js new file mode 100644 index 00000000..642af6d9 --- /dev/null +++ b/web/public/js/components/api-node/api-node-addresses-box.js @@ -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: `
+ +
+
+
+ {{addr.protocol}}://{{addr.host}}:{{addr.portRange}} + + +
+
+
+
+
+ +
+
` +}) \ No newline at end of file diff --git a/web/public/js/components/common/network-addresses-box.js b/web/public/js/components/common/network-addresses-box.js index eda60f67..38570ca7 100644 --- a/web/public/js/components/common/network-addresses-box.js +++ b/web/public/js/components/common/network-addresses-box.js @@ -1,5 +1,5 @@ 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 () { let addresses = this.vAddresses if (addresses == null) { @@ -9,9 +9,16 @@ Vue.component("network-addresses-box", { if (protocol == null) { protocol = "" } + + let name = this.vName + if (name == null) { + name = "addresses" + } + return { addresses: addresses, - protocol: protocol + protocol: protocol, + name: name } }, watch: { @@ -24,22 +31,28 @@ Vue.component("network-addresses-box", { let that = this teaweb.popup("/servers/addPortPopup?serverType=" + this.vServerType + "&protocol=" + this.protocol, { callback: function (resp) { - var addr = resp.data.address; - that.addresses.push(addr); + var addr = resp.data.address + that.addresses.push(addr) if (["https", "https4", "https6"].$contains(addr.protocol)) { - this.tlsProtocolName = "HTTPS"; + this.tlsProtocolName = "HTTPS" } else if (["tls", "tls4", "tls6"].$contains(addr.protocol)) { - this.tlsProtocolName = "TLS"; + this.tlsProtocolName = "TLS" } + + // 发送事件 + that.$emit("change", that.addresses) } }) }, removeAddr: function (index) { this.addresses.$remove(index); + + // 发送事件 + this.$emit("change", this.addresses) } }, template: `
- +
{{addr.protocol}}://{{addr.host}}*:{{addr.portRange}} diff --git a/web/public/js/components/common/size-capacity-view.js b/web/public/js/components/common/size-capacity-view.js new file mode 100644 index 00000000..ab45f455 --- /dev/null +++ b/web/public/js/components/common/size-capacity-view.js @@ -0,0 +1,7 @@ +Vue.component("size-capacity-view", { + props:["v-default-text", "v-value"], + template: `
+ {{vValue.count}}{{vValue.unit.toUpperCase()}} + {{vDefaultText}} +
` +}) \ No newline at end of file diff --git a/web/public/js/components/server/ssl-certs-box.js b/web/public/js/components/server/ssl-certs-box.js new file mode 100644 index 00000000..079cebd5 --- /dev/null +++ b/web/public/js/components/server/ssl-certs-box.js @@ -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: `
+ +
+
+ {{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   +
+
+
+
+ 选择或上传证书后HTTPSTLS服务才能生效。 +
+
+   + +
` +}) \ No newline at end of file diff --git a/web/views/@default/api/index.html b/web/views/@default/api/index.html index a6f1a94c..15c69f7b 100644 --- a/web/views/@default/api/index.html +++ b/web/views/@default/api/index.html @@ -8,15 +8,21 @@ 节点名称 - 主机地址 - 端口 + 访问地址 + 状态 操作 {{node.name}} - {{node.host}} - {{node.port}} + +
+ {{addr}} +
+ + + + 设置 diff --git a/web/views/@default/api/node/create.html b/web/views/@default/api/node/create.html index 5ea95ba6..ce7b406e 100644 --- a/web/views/@default/api/node/create.html +++ b/web/views/@default/api/node/create.html @@ -10,17 +10,23 @@ - 主机地址 * + 进程监听端口 * - -

IP地址或者域名。

+ +

API节点进程监听的网络端口。

+ + + + HTTPS证书 * + + - 端口 * + 外部访问地址 * - -

1-65535之间。

+ +

外部访问API节点的网络地址。

@@ -34,6 +40,15 @@ + + 是否启用 + +
+ + +
+ + diff --git a/web/views/@default/api/node/create.js b/web/views/@default/api/node/create.js index 04819c97..d2e97d54 100644 --- a/web/views/@default/api/node/create.js +++ b/web/views/@default/api/node/create.js @@ -1,3 +1,10 @@ Tea.context(function () { this.success = NotifySuccess("保存成功", "/api") + + this.hasHTTPS = false + this.changeListens = function (addrs) { + this.hasHTTPS = addrs.$any(function (k, v) { + return v.protocol == "https" + }) + } }) \ No newline at end of file diff --git a/web/views/@default/api/node/createAddrPopup.html b/web/views/@default/api/node/createAddrPopup.html new file mode 100644 index 00000000..ad88314b --- /dev/null +++ b/web/views/@default/api/node/createAddrPopup.html @@ -0,0 +1,24 @@ +{$layout "layout_popup"} + +

添加访问地址

+
+ + + + + + + + + +
网络协议 + +
访问地址 + +

可以是"IP:端口"或者"域名:端口"。

+
+ +
\ No newline at end of file diff --git a/web/views/@default/servers/components/cache/updatePopup.js b/web/views/@default/api/node/createAddrPopup.js similarity index 57% rename from web/views/@default/servers/components/cache/updatePopup.js rename to web/views/@default/api/node/createAddrPopup.js index 34fd51e4..c8fe9515 100644 --- a/web/views/@default/servers/components/cache/updatePopup.js +++ b/web/views/@default/api/node/createAddrPopup.js @@ -1,5 +1,3 @@ Tea.context(function () { this.success = NotifyPopup - - this.policyType = this.cachePolicy.type }) \ No newline at end of file diff --git a/web/views/@default/api/node/settings.html b/web/views/@default/api/node/settings.html index e8e1f139..8228b234 100644 --- a/web/views/@default/api/node/settings.html +++ b/web/views/@default/api/node/settings.html @@ -4,6 +4,7 @@
+ @@ -12,17 +13,23 @@ - + + + + + - + @@ -30,12 +37,21 @@ - - - - + + + + + + + +
节点名称 *
主机地址 *进程监听端口 * - -

IP地址或者域名。

+ +

API节点进程监听的网络端口。

+
HTTPS证书 * +
端口 *外部访问地址 * - -

1-65535之间。

+ +

外部访问API节点的网络地址。

描述 - -
描述 + +
是否启用 +
+ + +
+
diff --git a/web/views/@default/api/node/settings.js b/web/views/@default/api/node/settings.js index 182e566a..5c7da176 100644 --- a/web/views/@default/api/node/settings.js +++ b/web/views/@default/api/node/settings.js @@ -1,3 +1,12 @@ Tea.context(function () { 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" + }) + } }) \ No newline at end of file diff --git a/web/views/@default/api/node/updateAddrPopup.html b/web/views/@default/api/node/updateAddrPopup.html new file mode 100644 index 00000000..b78b042a --- /dev/null +++ b/web/views/@default/api/node/updateAddrPopup.html @@ -0,0 +1,24 @@ +{$layout "layout_popup"} + +

修改访问地址

+ + + + + + + + + + +
网络协议 + +
访问地址 + +

可以是"IP:端口"或者"域名:端口"。

+
+ +
\ No newline at end of file diff --git a/web/views/@default/api/node/updateAddrPopup.js b/web/views/@default/api/node/updateAddrPopup.js new file mode 100644 index 00000000..b98543ed --- /dev/null +++ b/web/views/@default/api/node/updateAddrPopup.js @@ -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 +}) \ No newline at end of file diff --git a/web/views/@default/servers/components/cache/@policy_menu.html b/web/views/@default/servers/components/cache/@policy_menu.html new file mode 100644 index 00000000..014c5bee --- /dev/null +++ b/web/views/@default/servers/components/cache/@policy_menu.html @@ -0,0 +1,11 @@ + + 列表 + | + {{cachePolicyName}} + 测试 + 统计 + 清理 + 删除 + 预热 + 修改 + diff --git a/web/views/@default/servers/components/cache/createPopup.html b/web/views/@default/servers/components/cache/createPopup.html index 49b8e7b1..31b0a712 100644 --- a/web/views/@default/servers/components/cache/createPopup.html +++ b/web/views/@default/servers/components/cache/createPopup.html @@ -9,7 +9,7 @@ - 缓存类型 * + 缓存类型 *

存放文件缓存的目录,通常填写绝对路径。

diff --git a/web/views/@default/servers/components/cache/index.html b/web/views/@default/servers/components/cache/index.html index 9ad0f1eb..951793d2 100644 --- a/web/views/@default/servers/components/cache/index.html +++ b/web/views/@default/servers/components/cache/index.html @@ -17,7 +17,7 @@ 容量 引用服务 状态 - 操作 + 操作 @@ -30,7 +30,7 @@ {{infos[index].countServers}} - 详情   修改   删除 + 详情   删除 diff --git a/web/views/@default/servers/components/cache/index.js b/web/views/@default/servers/components/cache/index.js index dbd62248..000e2669 100644 --- a/web/views/@default/servers/components/cache/index.js +++ b/web/views/@default/servers/components/cache/index.js @@ -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) { let that = this diff --git a/web/views/@default/servers/components/cache/policy.html b/web/views/@default/servers/components/cache/policy.html new file mode 100644 index 00000000..746040ba --- /dev/null +++ b/web/views/@default/servers/components/cache/policy.html @@ -0,0 +1,69 @@ +{$layout} +{$template "/left_menu"} + +
+ {$template "policy_menu"} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
策略名称{{cachePolicy.name}}
状态
缓存类型 + {{typeName}}({{cachePolicy.type}}) +
缓存目录 + {{cachePolicy.options.dir}} +

存放文件缓存的目录,通常填写绝对路径。

+
缓存最大容量 + +

允许缓存的最大内容长度,如果为0表示没有限制。

+
最大内容长度 + +

允许缓存的最大内容长度,如果为0表示没有限制。

+
容纳Key数量 + {{cachePolicy.maxKeys}} + 不限 +

可以容纳多少数量的Key,0表示不限制。

+
描述 + {{cachePolicy.description}} +
+
\ No newline at end of file diff --git a/web/views/@default/servers/components/cache/test.html b/web/views/@default/servers/components/cache/test.html new file mode 100644 index 00000000..91b45c44 --- /dev/null +++ b/web/views/@default/servers/components/cache/test.html @@ -0,0 +1,73 @@ +{$layout} +{$template "/left_menu"} + +
+ {$template "policy_menu"} + +

选择集群

+ + +
+ +

测试写入

+
+ + + + + + + + + + + + + + + +
Key + +
Value + +
操作结果 +
数据发送中...
+ 失败:{{writeMessage}} +
+ 此集群下没有任何可用的节点。 +
节点{{result.nodeName}}:{{result.message}}
+
+
+ 提交 +
+ +
+ +

测试读取

+
+ + + + + + + + + + + +
Key + +
操作结果 +
数据发送中...
+ 失败:{{readMessage}} +
+ 此集群下没有任何可用的节点。 +
节点{{result.nodeName}}:{{result.message}}
+
+
+ 提交 +
+
\ No newline at end of file diff --git a/web/views/@default/servers/components/cache/test.js b/web/views/@default/servers/components/cache/test.js new file mode 100644 index 00000000..3e64bf33 --- /dev/null +++ b/web/views/@default/servers/components/cache/test.js @@ -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 + } +}); \ No newline at end of file diff --git a/web/views/@default/servers/components/cache/update.html b/web/views/@default/servers/components/cache/update.html new file mode 100644 index 00000000..2147aed8 --- /dev/null +++ b/web/views/@default/servers/components/cache/update.html @@ -0,0 +1,79 @@ +{$layout} +{$template "/left_menu"} + +
+ {$template "policy_menu"} + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
策略名称 *
缓存类型 * + +
缓存目录 * + +

存放文件缓存的目录,通常填写绝对路径。

+
缓存最大容量 + +

允许缓存的最大内容长度,如果为0表示没有限制。

+
最大内容长度 + +

允许缓存的最大内容长度,如果为0表示没有限制。

+
容纳Key数量 + +

可以容纳多少数量的Key,0表示不限制。

+
描述 + +
是否启用 +
+ + +
+
+ +
+
\ No newline at end of file diff --git a/web/views/@default/servers/components/cache/update.js b/web/views/@default/servers/components/cache/update.js new file mode 100644 index 00000000..6d5dc6a5 --- /dev/null +++ b/web/views/@default/servers/components/cache/update.js @@ -0,0 +1,5 @@ +Tea.context(function () { + this.success = NotifyReloadSuccess("保存成功 ") + + this.policyType = this.cachePolicy.type +}) \ No newline at end of file diff --git a/web/views/@default/servers/components/cache/updatePopup.html b/web/views/@default/servers/components/cache/updatePopup.html deleted file mode 100644 index 03726cdf..00000000 --- a/web/views/@default/servers/components/cache/updatePopup.html +++ /dev/null @@ -1,76 +0,0 @@ -{$layout "layout_popup"} - -

修改缓存策略

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
策略名称 *
缓存类型 * - -
缓存目录 * - -

存放文件缓存的目录,通常填写绝对路径。

-
缓存最大容量 - -

允许缓存的最大内容长度,如果为0表示没有限制。

-
最大内容长度 - -

允许缓存的最大内容长度,如果为0表示没有限制。

-
容纳Key数量 - -

可以容纳多少数量的Key,0表示不限制。

-
描述 - -
是否启用 -
- - -
-
- -
\ No newline at end of file