租户项目粒度某类资源top数量 (#499)
* 租户项目粒度某类资源top数量 * 租户项目粒度某类资源top数量 * resname->rescate Co-authored-by: alickliming <alickliming@didi.global.com>
This commit is contained in:
parent
f9cfcaeabe
commit
a9cf307cbf
|
@ -77,3 +77,34 @@ func ResIdsGetByNodeIds(nids []int64) ([]int64, error) {
|
|||
err := DB["rdb"].Table(new(NodeResource)).In("node_id", nids).Select("res_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
// ResCountGetByNodeIdsAndWhere 根据叶子节点和Where条件获取资源数量表
|
||||
func ResCountGetByNodeIdsAndCate(nids []int64, cate string) (int, error) {
|
||||
if len(nids) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var nodeRess []NodeResource
|
||||
err := DB["rdb"].Table(new(NodeResource)).In("node_id", nids).Find(&nodeRess)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
cnt := 0
|
||||
for _, res := range nodeRess {
|
||||
res, err := ResourceGet("id=?", res.ResId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if res == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if res.Cate == cate {
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
|
||||
return cnt, nil
|
||||
}
|
||||
|
|
|
@ -87,6 +87,9 @@ func Config(r *gin.Engine) {
|
|||
rootLogin.GET("/sso/clients/:clientId", ssoClientGet)
|
||||
rootLogin.PUT("/sso/clients/:clientId", ssoClientPut)
|
||||
rootLogin.DELETE("/sso/clients/:clientId", ssoClientDel)
|
||||
|
||||
rootLogin.GET("/resources/tenant-rank", tenantResourcesCountRank)
|
||||
rootLogin.GET("/resources/project-rank", projectResourcesCountRank)
|
||||
}
|
||||
|
||||
userLogin := r.Group("/api/rdb").Use(shouldBeLogin())
|
||||
|
|
|
@ -2,6 +2,7 @@ package http
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -570,3 +571,176 @@ func renderAllResourcesCountByCate(c *gin.Context) {
|
|||
|
||||
renderData(c, list, nil)
|
||||
}
|
||||
|
||||
// 租户项目粒度资源排行
|
||||
type resourceRank struct {
|
||||
Name string `json:"name"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
func tenantResourcesCountRank(c *gin.Context) {
|
||||
resCate := queryStr(c, "resource_cate", "virtual")
|
||||
top := queryInt(c, "top", 0)
|
||||
if top < 0 {
|
||||
dangerous(fmt.Errorf("param top < 0"))
|
||||
}
|
||||
|
||||
tenantNode, err := models.NodeGets("cate=?", "tenant")
|
||||
dangerous(err)
|
||||
|
||||
tenantNodeLen := len(tenantNode)
|
||||
tenantNodeName := make(map[string]string, tenantNodeLen)
|
||||
for _, node := range tenantNode {
|
||||
if node.Ident != "" && node.Name != "" {
|
||||
tenantNodeName[node.Ident] = node.Name
|
||||
}
|
||||
}
|
||||
|
||||
ress, err := models.ResourceGets("cate=?", resCate)
|
||||
dangerous(err)
|
||||
|
||||
resMap := make(map[string]int, 50)
|
||||
for _, res := range ress {
|
||||
tenant := res.Tenant
|
||||
if tenant != "" {
|
||||
if _, ok := resMap[tenant]; !ok {
|
||||
resMap[tenant] = 0
|
||||
}
|
||||
|
||||
resMap[tenant]++
|
||||
}
|
||||
}
|
||||
|
||||
var ret []*resourceRank
|
||||
for k, v := range resMap {
|
||||
tR := new(resourceRank)
|
||||
name, ok := tenantNodeName[k]
|
||||
if !ok {
|
||||
name = k
|
||||
}
|
||||
tR.Name = name
|
||||
tR.Count = v
|
||||
|
||||
ret = append(ret, tR)
|
||||
}
|
||||
|
||||
retLen := len(ret)
|
||||
if retLen > 0 {
|
||||
sort.Slice(ret, func(i, j int) bool { return ret[i].Count > ret[j].Count })
|
||||
}
|
||||
|
||||
if top == 0 {
|
||||
renderData(c, ret, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if retLen > top {
|
||||
renderData(c, ret[:top], nil)
|
||||
return
|
||||
}
|
||||
|
||||
renderData(c, ret, nil)
|
||||
}
|
||||
|
||||
func projectResourcesCountRank(c *gin.Context) {
|
||||
resCate := queryStr(c, "resource_cate", "virtual")
|
||||
top := queryInt(c, "top", 0)
|
||||
if top < 0 {
|
||||
dangerous(fmt.Errorf("param top < 0"))
|
||||
}
|
||||
|
||||
// 获取全部project
|
||||
projectNodes, err := models.NodeGets("cate=?", "project")
|
||||
dangerous(err)
|
||||
|
||||
projectNodesLen := len(projectNodes)
|
||||
workerNum := 50
|
||||
if projectNodesLen < workerNum {
|
||||
workerNum = projectNodesLen
|
||||
}
|
||||
|
||||
worker := make(chan struct{}, workerNum) // 控制 goroutine 并发数
|
||||
dataChan := make(chan *resourceRank, projectNodesLen)
|
||||
|
||||
done := make(chan struct{}, 1)
|
||||
resp := make([]*resourceRank, 0)
|
||||
go func() {
|
||||
defer func() { done <- struct{}{} }()
|
||||
for d := range dataChan {
|
||||
resp = append(resp, d)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, pN := range projectNodes {
|
||||
worker <- struct{}{}
|
||||
go singleProjectResCount(pN.Id, resCate, worker,
|
||||
dataChan)
|
||||
}
|
||||
|
||||
// 等待所有 goroutine 执行完成
|
||||
for i := 0; i < workerNum; i++ {
|
||||
worker <- struct{}{}
|
||||
}
|
||||
close(dataChan)
|
||||
|
||||
// 等待所有 dataChan 被消费完
|
||||
<-done
|
||||
|
||||
//整理resp中数据
|
||||
respLen := len(resp)
|
||||
if respLen > 0 {
|
||||
sort.Slice(resp, func(i, j int) bool { return resp[i].Count > resp[j].Count })
|
||||
}
|
||||
|
||||
if top == 0 {
|
||||
renderData(c, resp, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if respLen > top {
|
||||
renderData(c, resp[:top], nil)
|
||||
return
|
||||
}
|
||||
|
||||
renderData(c, resp, nil)
|
||||
}
|
||||
|
||||
func singleProjectResCount(id int64, resCate string, worker chan struct{}, dataChan chan *resourceRank) {
|
||||
defer func() {
|
||||
<-worker
|
||||
}()
|
||||
|
||||
node, err := models.NodeGet("id=?", id)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if node == nil {
|
||||
logger.Errorf("node id %d is nil", id)
|
||||
return
|
||||
}
|
||||
|
||||
leafIds, err := node.LeafIds()
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
cnt, err := models.ResCountGetByNodeIdsAndCate(leafIds, resCate)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
data := new(resourceRank)
|
||||
nodeName := node.Name
|
||||
if nodeName != "" {
|
||||
data.Name = nodeName
|
||||
} else {
|
||||
data.Name = node.Ident
|
||||
}
|
||||
data.Count = cnt
|
||||
|
||||
dataChan <- data
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue