diff --git a/src/ac/iam/initial_instance_selections.go b/src/ac/iam/initial_instance_selections.go index 0d824c8ec9..c6d6d13992 100644 --- a/src/ac/iam/initial_instance_selections.go +++ b/src/ac/iam/initial_instance_selections.go @@ -89,14 +89,6 @@ func GenerateStaticInstanceSelections() []InstanceSelection { ResourceTypeChain: []ResourceChain{ // select the business at first. businessChain, - // { - // SystemID: SystemIDCMDB, - // ID: Set, - // }, - // { - // SystemID: SystemIDCMDB, - // ID: Module, - // }, // then select the host instances. { SystemID: SystemIDCMDB, @@ -296,5 +288,21 @@ func GenerateStaticInstanceSelections() []InstanceSelection { ID: GeneralCache, }}, }, + // only for other system's biz topo instance selection usage, not related to actions + { + ID: BizTopoSelection, + Name: "业务拓扑", + NameEn: "Business Topology", + ResourceTypeChain: []ResourceChain{ + businessChain, + { + SystemID: SystemIDCMDB, + ID: Set, + }, { + SystemID: SystemIDCMDB, + ID: Module, + }, + }, + }, } } diff --git a/src/ac/iam/initial_resources.go b/src/ac/iam/initial_resources.go index 49ebfc0040..d804cd677e 100644 --- a/src/ac/iam/initial_resources.go +++ b/src/ac/iam/initial_resources.go @@ -55,6 +55,8 @@ var ResourceTypeIDMap = map[TypeID]string{ BizProcessServiceTemplate: "服务模板", FieldGroupingTemplate: "字段组合模板", GeneralCache: "通用缓存", + Set: "集群", + Module: "模块", } // GenerateResourceTypes generate all the resource types registered to IAM. @@ -210,34 +212,34 @@ func genBusinessResources() []ResourceType { }, Version: 1, }, - // only for host topology usage, not related to actions - // { - // ID: Set, - // Name: ResourceTypeIDMap[Set], - // NameEn: "Set", - // Description: "集群列表", - // DescriptionEn: "all the sets in blueking cmdb.", - // Parents: []Parent{businessParent}, - // ProviderConfig: ResourceConfig{ - // Path: "/auth/v3/find/resource", - // }, - // Version: 1, - // }, - // { - // ID: Module, - // Name: ResourceTypeIDMap[Module], - // NameEn: "Module", - // Description: "模块列表", - // DescriptionEn: "all the modules in blueking cmdb.", - // Parents: []Parent{{ - // SystemID: SystemIDCMDB, - // ResourceID: Set, - // }}, - // ProviderConfig: ResourceConfig{ - // Path: "/auth/v3/find/resource", - // }, - // Version: 1, - // }, + // only for biz topology usage, not related to actions + { + ID: Set, + Name: ResourceTypeIDMap[Set], + NameEn: "Set", + Description: "业务拓扑集群", + DescriptionEn: "business topology set", + Parents: []Parent{businessParent}, + ProviderConfig: ResourceConfig{ + Path: "/auth/v3/find/resource", + }, + Version: 1, + }, + { + ID: Module, + Name: ResourceTypeIDMap[Module], + NameEn: "Module", + Description: "业务拓扑模块", + DescriptionEn: "business topology module", + Parents: []Parent{{ + SystemID: SystemIDCMDB, + ResourceID: Set, + }}, + ProviderConfig: ResourceConfig{ + Path: "/auth/v3/find/resource", + }, + Version: 1, + }, } } diff --git a/src/ac/iam/types.go b/src/ac/iam/types.go index 2482531f10..8fde86fcdc 100644 --- a/src/ac/iam/types.go +++ b/src/ac/iam/types.go @@ -226,6 +226,11 @@ const ( // GeneralCache defines general resource cache auth type GeneralCache TypeID = "general_cache" + // Set is set auth type + Set TypeID = "set" + // Module is module auth type + Module TypeID = "module" + // SkipType TODO // for resource type, which is not need to be authorized SkipType TypeID = "skip_type" @@ -743,6 +748,8 @@ const ( SysHostRscPoolDirectorySelection InstanceSelectionID = "sys_host_rsc_pool_directory" // GeneralCacheSelection general resource cache instance selection id GeneralCacheSelection InstanceSelectionID = "general_cache" + // BizTopoSelection is biz topo instance selection id + BizTopoSelection InstanceSelectionID = "biz_topo" ) // InstanceSelection TODO diff --git a/src/common/metadata/inst.go b/src/common/metadata/inst.go index 9082e8f060..88aa3d3a8c 100644 --- a/src/common/metadata/inst.go +++ b/src/common/metadata/inst.go @@ -30,6 +30,7 @@ type SetInst struct { SetEnv string `bson:"bk_set_env" json:"bk_set_env" mapstructure:"bk_set_env"` SetTemplateID int64 `bson:"set_template_id" json:"set_template_id" mapstructure:"set_template_id"` ParentID int64 `bson:"bk_parent_id" json:"bk_parent_id" mapstructure:"bk_parent_id"` + Default int `bson:"default" json:"default" field:"default" mapstructure:"default"` Creator string `field:"creator" json:"creator,omitempty" bson:"creator" mapstructure:"creator"` CreateTime Time `field:"create_time" json:"create_time,omitempty" bson:"create_time" mapstructure:"create_time"` diff --git a/src/common/metadata/instance_struct.go b/src/common/metadata/instance_struct.go index b26c3818da..ac4381cfd1 100644 --- a/src/common/metadata/instance_struct.go +++ b/src/common/metadata/instance_struct.go @@ -63,3 +63,17 @@ type ProcInstanceData struct { Count int `json:"count"` Info []Process `json:"info"` } + +// ResponseMainlineInst mainline instance response +// 只有主线模型实例的企业版本部分属性,使用前请注意 +type ResponseMainlineInst struct { + BaseResp `json:",inline"` + Data MainlineInstData `json:"data"` +} + +// MainlineInstData mainline instance data +// 只有主线模型实例的企业版本部分属性,使用前请注意 +type MainlineInstData struct { + Count int `json:"count"` + Info []MainlineInstInfo `json:"info"` +} diff --git a/src/scene_server/auth_server/logics/list_instance.go b/src/scene_server/auth_server/logics/list_instance.go index b81658d4e0..1d798864cd 100644 --- a/src/scene_server/auth_server/logics/list_instance.go +++ b/src/scene_server/auth_server/logics/list_instance.go @@ -476,3 +476,222 @@ func (lgc *Logics) ValidateListInstanceRequest(kit *rest.Kit, req *types.PullRes } return &filter, nil } + +// ListSetInstance list biz topo set instances +func (lgc *Logics) ListSetInstance(kit *rest.Kit, resourceType iam.TypeID, filter *types.ListInstanceFilter, + page types.Page) (*types.ListInstanceResult, error) { + + if filter == nil || filter.Parent == nil || filter.Parent.Type != iam.Business { + return &types.ListInstanceResult{Count: 0, Results: make([]types.InstanceResource, 0)}, nil + } + + bizID, err := strconv.ParseInt(filter.Parent.ID, 10, 64) + if err != nil { + blog.Errorf("parse filter.parent.id %s failed, err: %v, rid: %s", filter.Parent.ID, err, kit.Rid) + return &types.ListInstanceResult{Count: 0, Results: make([]types.InstanceResource, 0)}, nil + } + + // read mainline object association and construct mainline topo relation map + queryCond := &metadata.QueryCondition{ + Condition: map[string]interface{}{common.AssociationKindIDField: common.AssociationKindMainline}, + Fields: []string{common.BKObjIDField, common.BKAsstObjIDField}, + } + mlAsstRsp, err := lgc.CoreAPI.CoreService().Association().ReadModelAssociation(kit.Ctx, kit.Header, queryCond) + if err != nil { + blog.Errorf("search mainline association failed, err: %v, cond: %+v, rid: %s", err, queryCond, kit.Rid) + return nil, err + } + topoChildMap, topoParentMap := make(map[string]string), make(map[string]string) + for _, asst := range mlAsstRsp.Info { + if asst.ObjectID == common.BKInnerObjIDHost || asst.ObjectID == common.BKInnerObjIDModule { + continue + } + topoChildMap[asst.AsstObjID] = asst.ObjectID + topoParentMap[asst.ObjectID] = asst.AsstObjID + } + + // generate set cond by biz id and keyword + cond := make(mapstr.MapStr) + if len(filter.Keyword) != 0 { + cond, err = lgc.genSetKeywordCond(kit, bizID, topoChildMap, filter.Keyword) + if err != nil { + return nil, err + } + } + + cond[common.BKAppIDField] = bizID + setCond := &metadata.QueryCondition{ + Condition: cond, + Fields: []string{common.BKSetIDField, common.BKSetNameField, common.BKParentIDField, common.BKDefaultField}, + Page: metadata.BasePage{ + Limit: int(page.Limit), + Start: int(page.Offset), + }, + } + + return lgc.listSetInstance(kit, setCond, topoParentMap) +} + +func (lgc *Logics) genSetKeywordCond(kit *rest.Kit, bizID int64, topoChildMap map[string]string, keyword string) ( + map[string]interface{}, error) { + + // filter all mainline instances that matches the keyword + cond := mapstr.MapStr{ + common.BKInstNameField: mapstr.MapStr{ + common.BKDBLIKE: keyword, + common.BKDBOPTIONS: "i", + }, + common.BKAppIDField: bizID, + } + + for obj := topoChildMap[common.BKInnerObjIDApp]; obj != common.BKInnerObjIDSet; obj = topoChildMap[obj] { + instReq := &metadata.QueryCondition{ + Condition: cond, + Fields: []string{common.BKInstIDField}, + Page: metadata.BasePage{Limit: common.BKNoLimit}, + } + + instResp := new(metadata.ResponseMainlineInst) + err := lgc.CoreAPI.CoreService().Instance().ReadInstanceStruct(kit.Ctx, kit.Header, obj, instReq, instResp) + if err != nil { + blog.Errorf("search %s inst failed, err: %v, cond: %+v, rid: %s", obj, err, instReq, kit.Rid) + return nil, err + } + if err = instResp.CCError(); err != nil { + blog.Errorf("search %s inst failed, err: %v, cond: %+v, rid: %s", obj, err, instReq, kit.Rid) + return nil, err + } + + parentIDs := make([]int64, 0) + for _, inst := range instResp.Data.Info { + parentIDs = append(parentIDs, inst.InstID) + } + + cond = mapstr.MapStr{ + common.GetInstNameField(topoChildMap[obj]): mapstr.MapStr{ + common.BKDBLIKE: keyword, + common.BKDBOPTIONS: "i", + }, + } + + if len(parentIDs) != 0 { + cond = mapstr.MapStr{ + common.BKDBOR: []mapstr.MapStr{ + {common.BKParentIDField: mapstr.MapStr{common.BKDBIN: util.IntArrayUnique(parentIDs)}}, + cond, + }, + } + } + } + + return cond, nil +} + +func (lgc *Logics) listSetInstance(kit *rest.Kit, setCond *metadata.QueryCondition, topoParentMap map[string]string) ( + *types.ListInstanceResult, error) { + + // search set + setResp := new(metadata.ResponseSetInstance) + if err := lgc.CoreAPI.CoreService().Instance().ReadInstanceStruct(kit.Ctx, kit.Header, common.BKInnerObjIDSet, + setCond, setResp); err != nil { + blog.Errorf("search set failed, err: %v, cond: %+v, rid: %s", err, setCond, kit.Rid) + return nil, err + } + if err := setResp.CCError(); err != nil { + blog.Errorf("search set failed, err: %v, cond: %+v, rid: %s", err, setCond, kit.Rid) + return nil, err + } + + parentIDs := make([]int64, 0) + for _, set := range setResp.Data.Info { + if set.Default != common.DefaultResSetFlag { + parentIDs = append(parentIDs, set.ParentID) + } + } + + // get set parent mainline instance info + objInstMap := make(map[string]map[int64]metadata.MainlineInstInfo) + for obj := topoParentMap[common.BKInnerObjIDSet]; obj != common.BKInnerObjIDApp; obj = topoParentMap[obj] { + objInstMap[obj] = make(map[int64]metadata.MainlineInstInfo) + if len(parentIDs) == 0 { + break + } + parentIDs = util.IntArrayUnique(parentIDs) + + instCond := &metadata.QueryCondition{ + Condition: mapstr.MapStr{common.BKInstIDField: mapstr.MapStr{common.BKDBIN: parentIDs}}, + Fields: []string{common.BKInstIDField, common.BKInstNameField, common.BKParentIDField}, + Page: metadata.BasePage{Limit: len(parentIDs)}, + } + + instResp := new(metadata.ResponseMainlineInst) + err := lgc.CoreAPI.CoreService().Instance().ReadInstanceStruct(kit.Ctx, kit.Header, obj, instCond, instResp) + if err != nil { + blog.Errorf("search %s inst failed, err: %v, cond: %+v, rid: %s", obj, err, instCond, kit.Rid) + return nil, err + } + if err = instResp.CCError(); err != nil { + blog.Errorf("search %s inst failed, err: %v, cond: %+v, rid: %s", obj, err, instCond, kit.Rid) + return nil, err + } + + parentIDs = make([]int64, 0) + for _, inst := range instResp.Data.Info { + parentIDs = append(parentIDs, inst.ParentID) + objInstMap[obj][inst.InstID] = inst + } + } + + // add mainline topo path to set display name + instances := make([]types.InstanceResource, len(setResp.Data.Info)) + for i, set := range setResp.Data.Info { + instances[i] = types.InstanceResource{ + ID: strconv.FormatInt(set.SetID, 10), + DisplayName: set.SetName, + } + + // default set do not need to add mainline topo path + if set.Default == common.DefaultResSetFlag { + continue + } + + parentID := set.ParentID + for obj := topoParentMap[common.BKInnerObjIDSet]; obj != common.BKInnerObjIDApp; obj = topoParentMap[obj] { + instInfo, exists := objInstMap[obj][parentID] + if !exists { + break + } + instances[i].DisplayName = instInfo.InstName + " / " + instances[i].DisplayName + parentID = instInfo.ParentID + } + } + + return &types.ListInstanceResult{Count: int64(setResp.Data.Count), Results: instances}, nil +} + +// ListModuleInstance list biz topo module instances +func (lgc *Logics) ListModuleInstance(kit *rest.Kit, resourceType iam.TypeID, filter *types.ListInstanceFilter, + page types.Page) (*types.ListInstanceResult, error) { + + if filter == nil || filter.Parent == nil || filter.Parent.Type != iam.Set { + return &types.ListInstanceResult{Count: 0, Results: make([]types.InstanceResource, 0)}, nil + } + + setID, err := strconv.ParseInt(filter.Parent.ID, 10, 64) + if err != nil { + blog.Errorf("parse filter.parent.id %s failed, err: %v, rid: %s", filter.Parent.ID, err, kit.Rid) + return &types.ListInstanceResult{Count: 0, Results: make([]types.InstanceResource, 0)}, nil + } + + cond := map[string]interface{}{ + common.BKSetIDField: setID, + } + + if len(filter.Keyword) != 0 { + cond[common.BKModuleNameField] = map[string]interface{}{ + common.BKDBLIKE: filter.Keyword, + common.BKDBOPTIONS: "i", + } + } + return lgc.listInstance(kit, cond, resourceType, page) +} diff --git a/src/scene_server/auth_server/logics/parser.go b/src/scene_server/auth_server/logics/parser.go index 893f3ea3b5..7c8623a043 100644 --- a/src/scene_server/auth_server/logics/parser.go +++ b/src/scene_server/auth_server/logics/parser.go @@ -385,10 +385,10 @@ func GetResourceIDField(resourceType iam.TypeID) string { return common.BKAppIDField case iam.BizSet: return common.BKBizSetIDField - // case iam.Set: - // return common.BKSetIDField - // case iam.Module: - // return common.BKModuleIDField + case iam.Set: + return common.BKSetIDField + case iam.Module: + return common.BKModuleIDField default: if iam.IsIAMSysInstance(resourceType) { return common.BKInstIDField @@ -425,10 +425,10 @@ func GetResourceNameField(resourceType iam.TypeID) string { return common.BKFieldName case iam.Project: return common.BKProjectNameField - // case iam.Set: - // return common.BKSetNameField - // case iam.Module: - // return common.BKModuleNameField + case iam.Set: + return common.BKSetNameField + case iam.Module: + return common.BKModuleNameField default: if iam.IsIAMSysInstance(resourceType) { return common.BKInstNameField diff --git a/src/scene_server/auth_server/logics/util.go b/src/scene_server/auth_server/logics/util.go index f0f2971388..74dc4d35ed 100644 --- a/src/scene_server/auth_server/logics/util.go +++ b/src/scene_server/auth_server/logics/util.go @@ -64,10 +64,10 @@ func getResourceTableName(resourceType iam.TypeID) string { return common.BKTableNameBaseProject case iam.FieldGroupingTemplate: return common.BKTableNameFieldTemplate - // case iam.Set: - // return common.BKTableNameBaseSet - // case iam.Module: - // return common.BKTableNameBaseModule + case iam.Set: + return common.BKTableNameBaseSet + case iam.Module: + return common.BKTableNameBaseModule default: return "" } diff --git a/src/scene_server/auth_server/service/gen_method.go b/src/scene_server/auth_server/service/gen_method.go index 445eb6f452..56563a2d17 100644 --- a/src/scene_server/auth_server/service/gen_method.go +++ b/src/scene_server/auth_server/service/gen_method.go @@ -92,6 +92,10 @@ func (s *AuthService) genResourcePullMethod(kit *rest.Kit, resourceType iam.Type return s.genKubeWorkloadEventMethod(kit) case iam.GeneralCache: return genGeneralCacheMethod(kit) + case iam.Set: + return types.ResourcePullMethod{ListInstance: s.lgc.ListSetInstance}, nil + case iam.Module: + return types.ResourcePullMethod{ListInstance: s.lgc.ListModuleInstance}, nil default: if iam.IsIAMSysInstance(resourceType) { return types.ResourcePullMethod{