mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
fix: filter organization nodes by policy tags (#19507)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -180,6 +180,13 @@ type OrganizationNodeListInput struct {
|
||||
OrgType TOrgType `json:"org_type"`
|
||||
|
||||
Level int `json:"level"`
|
||||
|
||||
// domain tags filter imposed by policy
|
||||
PolicyDomainTags tagutils.TTagSetList `json:"policy_domain_tags"`
|
||||
// project tags filter imposed by policy
|
||||
PolicyProjectTags tagutils.TTagSetList `json:"policy_project_tags"`
|
||||
// object tags filter imposed by policy
|
||||
PolicyObjectTags tagutils.TTagSetList `json:"policy_object_tags"`
|
||||
}
|
||||
|
||||
type SProjectOrganization struct {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"database/sql"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
@@ -277,6 +278,27 @@ func (orgNode *SOrganizationNode) ValidateUpdateData(
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func tagSetList2Conditions(tagsetList tagutils.TTagSetList, keys []string, q *sqlchemy.SQuery) sqlchemy.ICondition {
|
||||
for i := range keys {
|
||||
if !strings.HasPrefix(keys[i], "org:") {
|
||||
keys[i] = "org:" + keys[i]
|
||||
}
|
||||
}
|
||||
conds := make([]sqlchemy.ICondition, 0)
|
||||
paths := tagutils.TagSetList2Paths(tagsetList, keys)
|
||||
for i := range paths {
|
||||
label := api.JoinLabels(paths[i]...)
|
||||
labelSlash := label + api.OrganizationLabelSeparator
|
||||
conds = append(conds, sqlchemy.Contains(q.Field("full_label"), labelSlash))
|
||||
conds = append(conds, sqlchemy.Startswith(q.Field("full_label"), labelSlash))
|
||||
conds = append(conds, sqlchemy.Equals(q.Field("full_label"), label))
|
||||
}
|
||||
if len(conds) > 0 {
|
||||
return sqlchemy.OR(conds...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 项目列表
|
||||
func (manager *SOrganizationNodeManager) ListItemFilter(
|
||||
ctx context.Context,
|
||||
@@ -300,7 +322,27 @@ func (manager *SOrganizationNodeManager) ListItemFilter(
|
||||
return nil, errors.Wrapf(err, "FetchByIdOrName %s", query.OrgId)
|
||||
}
|
||||
}
|
||||
q = q.Equals("org_id", orgObj.GetId())
|
||||
org := orgObj.(*SOrganization)
|
||||
q = q.Equals("org_id", org.GetId())
|
||||
|
||||
var cond sqlchemy.ICondition
|
||||
switch org.Type {
|
||||
case api.OrgTypeDomain:
|
||||
if !query.PolicyDomainTags.IsEmpty() {
|
||||
cond = tagSetList2Conditions(query.PolicyDomainTags, org.GetKeys(), q)
|
||||
}
|
||||
case api.OrgTypeProject:
|
||||
if !query.PolicyProjectTags.IsEmpty() {
|
||||
cond = tagSetList2Conditions(query.PolicyProjectTags, org.GetKeys(), q)
|
||||
}
|
||||
case api.OrgTypeObject:
|
||||
if !query.PolicyObjectTags.IsEmpty() {
|
||||
cond = tagSetList2Conditions(query.PolicyObjectTags, org.GetKeys(), q)
|
||||
}
|
||||
}
|
||||
if cond != nil {
|
||||
q = q.Filter(cond)
|
||||
}
|
||||
}
|
||||
|
||||
if len(query.OrgType) > 0 {
|
||||
|
||||
@@ -249,8 +249,6 @@ func (manager *SProjectManager) ListItemFilter(
|
||||
userCred mcclient.TokenCredential,
|
||||
query api.ProjectListInput,
|
||||
) (*sqlchemy.SQuery, error) {
|
||||
log.Debugf("ProjectManager ListItemFilter query %s", jsonutils.Marshal(query).String())
|
||||
|
||||
var err error
|
||||
|
||||
q, err = manager.SIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.IdentityBaseResourceListInput)
|
||||
|
||||
@@ -247,3 +247,36 @@ func TagsetMap2MapString(oTags map[string]TTagSet) map[string]string {
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func TagSet2Paths(tagSet TTagSet, keys []string) [][]string {
|
||||
ret := make([][]string, 0)
|
||||
tagMap := tagset2Map(tagSet)
|
||||
for _, k := range keys {
|
||||
if vs, ok := tagMap[k]; ok {
|
||||
nret := make([][]string, 0)
|
||||
for _, v := range vs {
|
||||
if len(ret) > 0 {
|
||||
for i := range ret {
|
||||
cret := make([]string, len(ret[i]), len(ret[i])+1)
|
||||
copy(cret, ret[i])
|
||||
cret = append(cret, v)
|
||||
nret = append(nret, cret)
|
||||
}
|
||||
} else {
|
||||
nret = append(nret, []string{v})
|
||||
}
|
||||
}
|
||||
ret = nret
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func TagSetList2Paths(tagsList TTagSetList, keys []string) [][]string {
|
||||
ret := make([][]string, 0)
|
||||
for i := range tagsList {
|
||||
paths := TagSet2Paths(tagsList[i], keys)
|
||||
ret = append(ret, paths...)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -633,3 +633,177 @@ func TestTagSetKeyPrefix(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagSet2Paths(t *testing.T) {
|
||||
cases := []struct {
|
||||
tagset TTagSet
|
||||
keys []string
|
||||
paths [][]string
|
||||
}{
|
||||
{
|
||||
tagset: TTagSet{
|
||||
{
|
||||
Key: "部门",
|
||||
Value: "技术",
|
||||
},
|
||||
{
|
||||
Key: "环境",
|
||||
Value: "测试",
|
||||
},
|
||||
},
|
||||
keys: []string{
|
||||
"部门", "环境",
|
||||
},
|
||||
paths: [][]string{
|
||||
{
|
||||
"技术", "测试",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
tagset: TTagSet{
|
||||
{
|
||||
Key: "部门",
|
||||
Value: "技术",
|
||||
},
|
||||
{
|
||||
Key: "环境",
|
||||
Value: "测试",
|
||||
},
|
||||
{
|
||||
Key: "环境",
|
||||
Value: "研发",
|
||||
},
|
||||
},
|
||||
keys: []string{
|
||||
"部门", "环境",
|
||||
},
|
||||
paths: [][]string{
|
||||
{
|
||||
"技术", "测试",
|
||||
},
|
||||
{
|
||||
"技术", "研发",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
tagset: TTagSet{
|
||||
{
|
||||
Key: "部门",
|
||||
Value: "技术",
|
||||
},
|
||||
{
|
||||
Key: "环境",
|
||||
Value: "测试",
|
||||
},
|
||||
{
|
||||
Key: "业务",
|
||||
Value: "TDCC",
|
||||
},
|
||||
},
|
||||
keys: []string{
|
||||
"业务", "部门", "环境",
|
||||
},
|
||||
paths: [][]string{
|
||||
{
|
||||
"TDCC", "技术", "测试",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
tagset: TTagSet{
|
||||
{
|
||||
Key: "部门",
|
||||
Value: "技术",
|
||||
},
|
||||
{
|
||||
Key: "环境",
|
||||
Value: "测试",
|
||||
},
|
||||
{
|
||||
Key: "业务",
|
||||
Value: "TDCC",
|
||||
},
|
||||
{
|
||||
Key: "业务",
|
||||
Value: "TKE",
|
||||
},
|
||||
},
|
||||
keys: []string{
|
||||
"业务", "部门", "环境",
|
||||
},
|
||||
paths: [][]string{
|
||||
{
|
||||
"TDCC", "技术", "测试",
|
||||
},
|
||||
{
|
||||
"TKE", "技术", "测试",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
tagset: TTagSet{
|
||||
{
|
||||
Key: "部门",
|
||||
Value: "技术",
|
||||
},
|
||||
{
|
||||
Key: "环境",
|
||||
Value: "测试",
|
||||
},
|
||||
{
|
||||
Key: "环境",
|
||||
Value: "生产",
|
||||
},
|
||||
{
|
||||
Key: "业务",
|
||||
Value: "TDCC",
|
||||
},
|
||||
{
|
||||
Key: "业务",
|
||||
Value: "TKE",
|
||||
},
|
||||
},
|
||||
keys: []string{
|
||||
"业务", "部门", "环境",
|
||||
},
|
||||
paths: [][]string{
|
||||
{
|
||||
"TDCC", "技术", "测试",
|
||||
},
|
||||
{
|
||||
"TKE", "技术", "测试",
|
||||
},
|
||||
{
|
||||
"TDCC", "技术", "生产",
|
||||
},
|
||||
{
|
||||
"TKE", "技术", "生产",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
tagset: TTagSet{
|
||||
{
|
||||
Key: "org:系统",
|
||||
Value: "G-BOOK",
|
||||
},
|
||||
},
|
||||
keys: []string{
|
||||
"org:系统", "org:业务模块", "org:環境",
|
||||
},
|
||||
paths: [][]string{
|
||||
{
|
||||
"G-BOOK",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
paths := TagSet2Paths(c.tagset, c.keys)
|
||||
if jsonutils.Marshal(paths).String() != jsonutils.Marshal(c.paths).String() {
|
||||
t.Errorf("tagset: %s keys: %s want %s got %s", jsonutils.Marshal(c.tagset), jsonutils.Marshal(c.keys), jsonutils.Marshal(c.paths), jsonutils.Marshal(paths))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user