From 7eecf3cec380bbea82a1f49ac1b6686d87fdb8fc Mon Sep 17 00:00:00 2001 From: pycook Date: Thu, 26 Sep 2024 20:32:21 +0800 Subject: [PATCH] feat(api): add api /ci_type_relations/path --- cmdb-api/api/lib/cmdb/ci_type.py | 24 +++++++++++++++++++ .../api/lib/cmdb/search/ci_relation/search.py | 10 ++++++++ cmdb-api/api/views/cmdb/ci_type_relation.py | 16 +++++++++++-- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/cmdb-api/api/lib/cmdb/ci_type.py b/cmdb-api/api/lib/cmdb/ci_type.py index d93dfb6..9ede428 100644 --- a/cmdb-api/api/lib/cmdb/ci_type.py +++ b/cmdb-api/api/lib/cmdb/ci_type.py @@ -3,6 +3,7 @@ from collections import defaultdict import copy +import networkx as nx import toposort from flask import abort from flask import current_app @@ -845,6 +846,29 @@ class CITypeRelationManager(object): return ids + @staticmethod + def find_path(source_type_id, target_type_ids): + source_type_id = int(source_type_id) + target_type_ids = map(int, target_type_ids) + + graph = nx.DiGraph() + + def get_children(_id): + children = CITypeRelation.get_by(parent_id=_id, to_dict=False) + + for i in children: + if i.child_id != _id: + graph.add_edge(i.parent_id, i.child_id) + get_children(i.child_id) + + get_children(source_type_id) + + paths = list(nx.all_simple_paths(graph, source_type_id, target_type_ids)) + + del graph + + return paths + @staticmethod def _wrap_relation_type_dict(type_id, relation_inst): ci_type_dict = CITypeCache.get(type_id).to_dict() diff --git a/cmdb-api/api/lib/cmdb/search/ci_relation/search.py b/cmdb-api/api/lib/cmdb/search/ci_relation/search.py index 36e7e49..a56a41f 100644 --- a/cmdb-api/api/lib/cmdb/search/ci_relation/search.py +++ b/cmdb-api/api/lib/cmdb/search/ci_relation/search.py @@ -432,6 +432,13 @@ class Search(object): return SearchFromDB(q, use_ci_filter=True, only_ids=True, count=100000).search() + @staticmethod + def _filter_target_ids(target_ids, type_ids, q): + if not q.startswith('_type:'): + q = "_type:({}),{}".format(";".join(map(str, type_ids)), q) + + return SearchFromDB(q, ci_ids=target_ids, use_ci_filter=False, only_ids=True, count=100000).search() + @staticmethod def _path2level(src_type_id, target_type_ids, path): if not src_type_id or not target_type_ids: @@ -502,6 +509,7 @@ class Search(object): ci_ids = [j for i in paths for j in i] response, _, _, _, _, _ = SearchFromDB("_type:({})".format(";".join(map(str, types))), + use_ci_filter=False, ci_ids=list(map(int, ci_ids)), count=1000000).search() id2ci = {str(i.get('_id')): i for i in response} @@ -539,6 +547,8 @@ class Search(object): source_ids = self._get_src_ids(source) graph, target_ids = self._build_graph(source_ids, level2type, target['type_ids'], acl) + if target.get('q'): + target_ids = self._filter_target_ids(target_ids, target['type_ids'], target['q']) paths = self._find_paths(graph, source_ids, set(target_ids)) del graph diff --git a/cmdb-api/api/views/cmdb/ci_type_relation.py b/cmdb-api/api/views/cmdb/ci_type_relation.py index cac6371..060eaaa 100644 --- a/cmdb-api/api/views/cmdb/ci_type_relation.py +++ b/cmdb-api/api/views/cmdb/ci_type_relation.py @@ -8,7 +8,6 @@ from api.lib.cmdb.ci_type import CITypeManager from api.lib.cmdb.ci_type import CITypeRelationManager from api.lib.cmdb.const import PermEnum from api.lib.cmdb.const import ResourceTypeEnum -from api.lib.cmdb.const import RoleEnum from api.lib.cmdb.preference import PreferenceManager from api.lib.cmdb.resp_format import ErrFormat from api.lib.common_setting.decorator import perms_role_required @@ -17,7 +16,7 @@ from api.lib.decorator import args_required from api.lib.perm.acl.acl import ACLManager from api.lib.perm.acl.acl import has_perm_from_args from api.lib.perm.acl.acl import is_app_admin -from api.lib.perm.acl.acl import role_required +from api.lib.utils import handle_arg_list from api.resource import APIView app_cli = CMDBApp() @@ -42,6 +41,19 @@ class GetParentsView(APIView): return self.jsonify(parents=CITypeRelationManager.get_parents(child_id)) +class CITypeRelationPathView(APIView): + url_prefix = ("/ci_type_relations/path",) + + @args_required("source_type_id", "target_type_ids") + def get(self): + source_type_id = request.values.get("source_type_id") + target_type_ids = handle_arg_list(request.values.get("target_type_ids")) + + paths = CITypeRelationManager.find_path(source_type_id, target_type_ids) + + return self.jsonify(paths=paths) + + class CITypeRelationView(APIView): url_prefix = ("/ci_type_relations", "/ci_type_relations//")