diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go index 8f20efc6..75d55a5b 100644 --- a/internal/rpc/rpc_client.go +++ b/internal/rpc/rpc_client.go @@ -332,6 +332,10 @@ func (this *RPCClient) AuthorityKeyRPC() pb.AuthorityKeyServiceClient { return pb.NewAuthorityKeyServiceClient(this.pickConn()) } +func (this *RPCClient) AuthorityNodeRPC() pb.AuthorityNodeServiceClient { + return pb.NewAuthorityNodeServiceClient(this.pickConn()) +} + // Context 构造Admin上下文 func (this *RPCClient) Context(adminId int64) context.Context { ctx := context.Background() diff --git a/internal/web/actions/default/settings/authority/index.go b/internal/web/actions/default/settings/authority/index.go index 8bf85536..30e43031 100644 --- a/internal/web/actions/default/settings/authority/index.go +++ b/internal/web/actions/default/settings/authority/index.go @@ -15,7 +15,7 @@ type IndexAction struct { } func (this *IndexAction) Init() { - this.Nav("", "", "") + this.Nav("", "", "index") } func (this *IndexAction) RunGet(params struct{}) { @@ -47,5 +47,23 @@ func (this *IndexAction) RunGet(params struct{}) { } this.Data["key"] = keyMap + // 检查是否有认证节点,如果没有认证节点,则自动生成一个 + countResp, err := this.RPC().AuthorityNodeRPC().CountAllEnabledAuthorityNodes(this.AdminContext(), &pb.CountAllEnabledAuthorityNodesRequest{}) + if err != nil { + this.ErrorPage(err) + return + } + if countResp.Count == 0 { + _, err = this.RPC().AuthorityNodeRPC().CreateAuthorityNode(this.AdminContext(), &pb.CreateAuthorityNodeRequest{ + Name: "默认节点", + Description: "系统自动生成的默认节点", + IsOn: true, + }) + if err != nil { + this.ErrorPage(err) + return + } + } + this.Show() } diff --git a/internal/web/actions/default/settings/authority/nodes/delete.go b/internal/web/actions/default/settings/authority/nodes/delete.go new file mode 100644 index 00000000..afd587cb --- /dev/null +++ b/internal/web/actions/default/settings/authority/nodes/delete.go @@ -0,0 +1,28 @@ +package nodes + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/oplogs" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" +) + +type DeleteAction struct { + actionutils.ParentAction +} + +func (this *DeleteAction) RunPost(params struct { + NodeId int64 +}) { + // TODO 检查权限 + + _, err := this.RPC().AuthorityNodeRPC().DeleteAuthorityNode(this.AdminContext(), &pb.DeleteAuthorityNodeRequest{NodeId: params.NodeId}) + if err != nil { + this.ErrorPage(err) + return + } + + // 创建日志 + defer this.CreateLog(oplogs.LevelInfo, "删除认证节点 %d", params.NodeId) + + this.Success() +} diff --git a/internal/web/actions/default/settings/authority/nodes/helper.go b/internal/web/actions/default/settings/authority/nodes/helper.go new file mode 100644 index 00000000..b676b483 --- /dev/null +++ b/internal/web/actions/default/settings/authority/nodes/helper.go @@ -0,0 +1,15 @@ +package nodes + +import ( + "github.com/iwind/TeaGo/actions" +) + +type Helper struct { +} + +func NewHelper() *Helper { + return &Helper{} +} + +func (this *Helper) BeforeAction(action *actions.ActionObject) { +} diff --git a/internal/web/actions/default/settings/authority/nodes/index.go b/internal/web/actions/default/settings/authority/nodes/index.go new file mode 100644 index 00000000..08937b9f --- /dev/null +++ b/internal/web/actions/default/settings/authority/nodes/index.go @@ -0,0 +1,75 @@ +package nodes + +import ( + "encoding/json" + "fmt" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/logs" + "github.com/iwind/TeaGo/maps" + "time" +) + +type IndexAction struct { + actionutils.ParentAction +} + +func (this *IndexAction) Init() { + this.Nav("", "node", "node") +} + +func (this *IndexAction) RunGet(params struct{}) { + countResp, err := this.RPC().AuthorityNodeRPC().CountAllEnabledAuthorityNodes(this.AdminContext(), &pb.CountAllEnabledAuthorityNodesRequest{}) + if err != nil { + this.ErrorPage(err) + return + } + count := countResp.Count + page := this.NewPage(count) + this.Data["page"] = page.AsHTML() + + nodeMaps := []maps.Map{} + if count > 0 { + nodesResp, err := this.RPC().AuthorityNodeRPC().ListEnabledAuthorityNodes(this.AdminContext(), &pb.ListEnabledAuthorityNodesRequest{ + Offset: page.Offset, + Size: page.Size, + }) + if err != nil { + this.ErrorPage(err) + return + } + + for _, node := range nodesResp.Nodes { + // 状态 + status := &nodeconfigs.NodeStatus{} + if len(node.StatusJSON) > 0 { + err = json.Unmarshal(node.StatusJSON, &status) + if err != nil { + logs.Error(err) + continue + } + status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃 + } + + nodeMaps = append(nodeMaps, maps.Map{ + "id": node.Id, + "isOn": node.IsOn, + "name": node.Name, + "status": maps.Map{ + "isActive": status.IsActive, + "updatedAt": status.UpdatedAt, + "hostname": status.Hostname, + "cpuUsage": status.CPUUsage, + "cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100), + "memUsage": status.MemoryUsage, + "memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100), + "buildVersion": status.BuildVersion, + }, + }) + } + } + this.Data["nodes"] = nodeMaps + + this.Show() +} diff --git a/internal/web/actions/default/settings/authority/nodes/init.go b/internal/web/actions/default/settings/authority/nodes/init.go new file mode 100644 index 00000000..d50148ef --- /dev/null +++ b/internal/web/actions/default/settings/authority/nodes/init.go @@ -0,0 +1,23 @@ +package nodes + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/configloaders" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/authority/nodes/node" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" + "github.com/iwind/TeaGo" +) + +func init() { + TeaGo.BeforeStart(func(server *TeaGo.Server) { + server. + Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)). + Helper(NewHelper()). + Helper(settingutils.NewAdvancedHelper("authority")). + Prefix("/settings/authority/nodes"). + Get("", new(IndexAction)). + GetPost("/node/createPopup", new(node.CreatePopupAction)). + Post("/delete", new(DeleteAction)). + EndAll() + }) +} diff --git a/internal/web/actions/default/settings/authority/nodes/node/createPopup.go b/internal/web/actions/default/settings/authority/nodes/node/createPopup.go new file mode 100644 index 00000000..034285e4 --- /dev/null +++ b/internal/web/actions/default/settings/authority/nodes/node/createPopup.go @@ -0,0 +1,47 @@ +package node + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/oplogs" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/actions" +) + +type CreatePopupAction struct { + actionutils.ParentAction +} + +func (this *CreatePopupAction) Init() { + this.Nav("", "node", "create") +} + +func (this *CreatePopupAction) RunGet(params struct{}) { + this.Show() +} + +func (this *CreatePopupAction) RunPost(params struct { + Name string + Description string + IsOn bool + + Must *actions.Must +}) { + params.Must. + Field("name", params.Name). + Require("请输入认证节点名称") + + createResp, err := this.RPC().AuthorityNodeRPC().CreateAuthorityNode(this.AdminContext(), &pb.CreateAuthorityNodeRequest{ + Name: params.Name, + Description: params.Description, + IsOn: params.IsOn, + }) + if err != nil { + this.ErrorPage(err) + return + } + + // 创建日志 + defer this.CreateLog(oplogs.LevelInfo, "创建认证节点 %d", createResp.NodeId) + + this.Success() +} diff --git a/internal/web/actions/default/settings/authority/nodes/node/helper.go b/internal/web/actions/default/settings/authority/nodes/node/helper.go new file mode 100644 index 00000000..689a22cc --- /dev/null +++ b/internal/web/actions/default/settings/authority/nodes/node/helper.go @@ -0,0 +1,21 @@ +package node + +import ( + "github.com/iwind/TeaGo/actions" + "net/http" +) + +type Helper struct { +} + +func NewHelper() *Helper { + return &Helper{} +} + +func (this *Helper) BeforeAction(action *actions.ActionObject) (goNext bool) { + if action.Request.Method != http.MethodGet { + return true + } + + return true +} diff --git a/internal/web/actions/default/settings/authority/nodes/node/index.go b/internal/web/actions/default/settings/authority/nodes/node/index.go new file mode 100644 index 00000000..085413d6 --- /dev/null +++ b/internal/web/actions/default/settings/authority/nodes/node/index.go @@ -0,0 +1,39 @@ +package node + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) + +type IndexAction struct { + actionutils.ParentAction +} + +func (this *IndexAction) Init() { + this.Nav("", "", "index") +} + +func (this *IndexAction) RunGet(params struct { + NodeId int64 +}) { + nodeResp, err := this.RPC().AuthorityNodeRPC().FindEnabledAuthorityNode(this.AdminContext(), &pb.FindEnabledAuthorityNodeRequest{NodeId: params.NodeId}) + if err != nil { + this.ErrorPage(err) + return + } + node := nodeResp.Node + if node == nil { + this.NotFound("authorityNode", params.NodeId) + return + } + + this.Data["node"] = maps.Map{ + "id": node.Id, + "name": node.Name, + "description": node.Description, + "isOn": node.IsOn, + } + + this.Show() +} diff --git a/internal/web/actions/default/settings/authority/nodes/node/init.go b/internal/web/actions/default/settings/authority/nodes/node/init.go new file mode 100644 index 00000000..489ebfbf --- /dev/null +++ b/internal/web/actions/default/settings/authority/nodes/node/init.go @@ -0,0 +1,25 @@ +package node + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/configloaders" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" + "github.com/iwind/TeaGo" +) + +func init() { + TeaGo.BeforeStart(func(server *TeaGo.Server) { + server. + Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)). + Helper(settingutils.NewAdvancedHelper("authority")). + Prefix("/settings/authority/nodes/node"). + + // 节点相关 + Helper(NewHelper()). + Get("", new(IndexAction)). + GetPost("/update", new(UpdateAction)). + Get("/install", new(InstallAction)). + + EndAll() + }) +} diff --git a/internal/web/actions/default/settings/authority/nodes/node/install.go b/internal/web/actions/default/settings/authority/nodes/node/install.go new file mode 100644 index 00000000..47f2675d --- /dev/null +++ b/internal/web/actions/default/settings/authority/nodes/node/install.go @@ -0,0 +1,57 @@ +package node + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" + "strings" +) + +type InstallAction struct { + actionutils.ParentAction +} + +func (this *InstallAction) Init() { + this.Nav("", "", "install") +} + +func (this *InstallAction) RunGet(params struct { + NodeId int64 +}) { + // 认证节点信息 + nodeResp, err := this.RPC().AuthorityNodeRPC().FindEnabledAuthorityNode(this.AdminContext(), &pb.FindEnabledAuthorityNodeRequest{NodeId: params.NodeId}) + if err != nil { + this.ErrorPage(err) + return + } + node := nodeResp.Node + if node == nil { + this.NotFound("authorityNode", params.NodeId) + return + } + + this.Data["node"] = maps.Map{ + "id": node.Id, + "name": node.Name, + "uniqueId": node.UniqueId, + "secret": node.Secret, + } + + // API节点列表 + apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{}) + if err != nil { + this.ErrorPage(err) + return + } + apiNodes := apiNodesResp.Nodes + apiEndpoints := []string{} + for _, apiNode := range apiNodes { + if !apiNode.IsOn { + continue + } + apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...) + } + this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\"" + + this.Show() +} diff --git a/internal/web/actions/default/settings/authority/nodes/node/update.go b/internal/web/actions/default/settings/authority/nodes/node/update.go new file mode 100644 index 00000000..bd32a258 --- /dev/null +++ b/internal/web/actions/default/settings/authority/nodes/node/update.go @@ -0,0 +1,73 @@ +package node + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/oplogs" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/actions" + "github.com/iwind/TeaGo/maps" +) + +type UpdateAction struct { + actionutils.ParentAction +} + +func (this *UpdateAction) Init() { + this.Nav("", "", "update") +} + +func (this *UpdateAction) RunGet(params struct { + NodeId int64 +}) { + nodeResp, err := this.RPC().AuthorityNodeRPC().FindEnabledAuthorityNode(this.AdminContext(), &pb.FindEnabledAuthorityNodeRequest{ + NodeId: params.NodeId, + }) + if err != nil { + this.ErrorPage(err) + return + } + node := nodeResp.Node + if node == nil { + this.WriteString("要操作的节点不存在") + return + } + + this.Data["node"] = maps.Map{ + "id": node.Id, + "name": node.Name, + "description": node.Description, + "isOn": node.IsOn, + } + + this.Show() +} + +// 保存基础设置 +func (this *UpdateAction) RunPost(params struct { + NodeId int64 + Name string + Description string + IsOn bool + + Must *actions.Must +}) { + params.Must. + Field("name", params.Name). + Require("请输入认证节点名称") + + _, err := this.RPC().AuthorityNodeRPC().UpdateAuthorityNode(this.AdminContext(), &pb.UpdateAuthorityNodeRequest{ + NodeId: params.NodeId, + Name: params.Name, + Description: params.Description, + IsOn: params.IsOn, + }) + if err != nil { + this.ErrorPage(err) + return + } + + // 创建日志 + defer this.CreateLog(oplogs.LevelInfo, "修改认证节点 %d", params.NodeId) + + this.Success() +} diff --git a/internal/web/import.go b/internal/web/import.go index 260e53df..fdcb58b1 100644 --- a/internal/web/import.go +++ b/internal/web/import.go @@ -85,6 +85,8 @@ import ( _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/stat" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/authority" + _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/authority/nodes" + _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/authority/nodes/node" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/backup" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/database" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/ip-library" diff --git a/web/views/@default/settings/authority/@menu.html b/web/views/@default/settings/authority/@menu.html new file mode 100644 index 00000000..43beab87 --- /dev/null +++ b/web/views/@default/settings/authority/@menu.html @@ -0,0 +1,4 @@ + + 认证信息 + 认证节点 + \ No newline at end of file diff --git a/web/views/@default/settings/authority/index.html b/web/views/@default/settings/authority/index.html index 70f5546a..536ea043 100644 --- a/web/views/@default/settings/authority/index.html +++ b/web/views/@default/settings/authority/index.html @@ -1,4 +1,5 @@ {$layout} +{$template "menu"}
认证之后,可以使用企业版功能,当前你还没有认证,[在这里看认证方法]
diff --git a/web/views/@default/settings/authority/nodes/index.html b/web/views/@default/settings/authority/nodes/index.html new file mode 100644 index 00000000..c98c2f23 --- /dev/null +++ b/web/views/@default/settings/authority/nodes/index.html @@ -0,0 +1,50 @@ +{$layout} +{$template "../menu"} + + + +

暂时还没有节点。

+ + + + + + + + + + + + + + + + + + + + +
节点名称版本号CPU内存状态操作
{{node.name}} + v{{node.status.buildVersion}} + - + + {{node.status.cpuUsageText}} + - + + {{node.status.memUsageText}} + - + + +
+ 运行中 +
+ 已断开 + 未连接 +
+ 详情   + 删除 +
+ +
\ No newline at end of file diff --git a/web/views/@default/settings/authority/nodes/index.js b/web/views/@default/settings/authority/nodes/index.js new file mode 100644 index 00000000..1738e4a8 --- /dev/null +++ b/web/views/@default/settings/authority/nodes/index.js @@ -0,0 +1,26 @@ +Tea.context(function () { + // 创建节点 + this.createNode = function () { + teaweb.popup("/settings/authority/nodes/node/createPopup", { + width: "50em", + height: "30em", + callback: function () { + teaweb.success("保存成功", function () { + teaweb.reload() + }) + } + }) + } + + // 删除节点 + this.deleteNode = function (nodeId) { + let that = this + teaweb.confirm("确定要删除此节点吗?", function () { + that.$post("/settings/authority/nodes/delete") + .params({ + nodeId: nodeId + }) + .refresh() + }) + } +}) \ No newline at end of file diff --git a/web/views/@default/settings/authority/nodes/node/@menu.html b/web/views/@default/settings/authority/nodes/node/@menu.html new file mode 100644 index 00000000..8afccb48 --- /dev/null +++ b/web/views/@default/settings/authority/nodes/node/@menu.html @@ -0,0 +1,7 @@ + + 节点列表 + | + "{{node.name}}"详情 + 安装节点 + 修改节点 + diff --git a/web/views/@default/settings/authority/nodes/node/createPopup.html b/web/views/@default/settings/authority/nodes/node/createPopup.html new file mode 100644 index 00000000..a4c6995e --- /dev/null +++ b/web/views/@default/settings/authority/nodes/node/createPopup.html @@ -0,0 +1,34 @@ +{$layout "layout_popup"} + +

添加认证节点

+
+ + + + + + + + + + + + + + + + + + +
节点名称 * + +
描述 + +
是否启用 +
+ + +
+
+ +
\ No newline at end of file diff --git a/web/views/@default/settings/authority/nodes/node/createPopup.js b/web/views/@default/settings/authority/nodes/node/createPopup.js new file mode 100644 index 00000000..c6471490 --- /dev/null +++ b/web/views/@default/settings/authority/nodes/node/createPopup.js @@ -0,0 +1,3 @@ +Tea.context(function () { + +}) \ No newline at end of file diff --git a/web/views/@default/settings/authority/nodes/node/index.html b/web/views/@default/settings/authority/nodes/node/index.html new file mode 100644 index 00000000..fb9a5f7b --- /dev/null +++ b/web/views/@default/settings/authority/nodes/node/index.html @@ -0,0 +1,24 @@ +{$layout} +{$template "menu"} + + + + + + + + + + + + + + +
节点名称 + {{node.name}} +
状态 + +
描述 + {{node.description}} + 暂时还没有描述。 +
\ No newline at end of file diff --git a/web/views/@default/settings/authority/nodes/node/install.html b/web/views/@default/settings/authority/nodes/node/install.html new file mode 100644 index 00000000..7846cfd7 --- /dev/null +++ b/web/views/@default/settings/authority/nodes/node/install.html @@ -0,0 +1,23 @@ +{$layout} +{$template "menu"} + +

安装步骤

+
    +
  1. 按照下面的配置信息替换configs/api.yaml内容
  2. +
  3. 使用bin/edge-authority start启动节点
  4. +
  5. 可以在logs/run.log中查看启动是否有异常
  6. +
+ +
+

配置信息

+ + + + + +
configs/api.yaml
[下载]
+
rpc:
+  endpoints: [ {{apiEndpoints}} ]
+nodeId: "{{node.uniqueId}}"
+secret: "{{node.secret}}"
+
diff --git a/web/views/@default/settings/authority/nodes/node/update.html b/web/views/@default/settings/authority/nodes/node/update.html new file mode 100644 index 00000000..401969a1 --- /dev/null +++ b/web/views/@default/settings/authority/nodes/node/update.html @@ -0,0 +1,37 @@ +{$layout} + +{$template "menu"} + +
+ + + + + + + + + + + + + + + + + + + + +
节点名称 * + +
描述 + +
是否启用 +
+ + +
+
+ +
\ No newline at end of file diff --git a/web/views/@default/settings/authority/nodes/node/update.js b/web/views/@default/settings/authority/nodes/node/update.js new file mode 100644 index 00000000..14d72f20 --- /dev/null +++ b/web/views/@default/settings/authority/nodes/node/update.js @@ -0,0 +1,3 @@ +Tea.context(function () { + this.success = NotifySuccess("保存成功", "/settings/authority/nodes/node?nodeId=" + this.node.id) +}) \ No newline at end of file