Browse Source

租户项目粒度某类资源top数量 (#499)

* 租户项目粒度某类资源top数量

* 租户项目粒度某类资源top数量

* resname->rescate

Co-authored-by: alickliming <alickliming@didi.global.com>
tags/v5.8.0
alick-liming GitHub 5 years ago
parent
commit
a9cf307cbf
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 208 additions and 0 deletions
  1. +31
    -0
      src/models/node_resource.go
  2. +3
    -0
      src/modules/rdb/http/router.go
  3. +174
    -0
      src/modules/rdb/http/router_resource.go

+ 31
- 0
src/models/node_resource.go View File

@@ -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) err := DB["rdb"].Table(new(NodeResource)).In("node_id", nids).Select("res_id").Find(&ids)
return ids, err 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
}

+ 3
- 0
src/modules/rdb/http/router.go View File

@@ -87,6 +87,9 @@ func Config(r *gin.Engine) {
rootLogin.GET("/sso/clients/:clientId", ssoClientGet) rootLogin.GET("/sso/clients/:clientId", ssoClientGet)
rootLogin.PUT("/sso/clients/:clientId", ssoClientPut) rootLogin.PUT("/sso/clients/:clientId", ssoClientPut)
rootLogin.DELETE("/sso/clients/:clientId", ssoClientDel) 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()) userLogin := r.Group("/api/rdb").Use(shouldBeLogin())


+ 174
- 0
src/modules/rdb/http/router_resource.go View File

@@ -2,6 +2,7 @@ package http


import ( import (
"fmt" "fmt"
"sort"
"strings" "strings"


"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -570,3 +571,176 @@ func renderAllResourcesCountByCate(c *gin.Context) {


renderData(c, list, nil) 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…
Cancel
Save