feat(api): add api /ci_type_relations/path

This commit is contained in:
pycook 2024-09-26 20:32:21 +08:00
parent 857cbd82fd
commit 7eecf3cec3
3 changed files with 48 additions and 2 deletions

View File

@ -3,6 +3,7 @@
from collections import defaultdict from collections import defaultdict
import copy import copy
import networkx as nx
import toposort import toposort
from flask import abort from flask import abort
from flask import current_app from flask import current_app
@ -845,6 +846,29 @@ class CITypeRelationManager(object):
return ids 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 @staticmethod
def _wrap_relation_type_dict(type_id, relation_inst): def _wrap_relation_type_dict(type_id, relation_inst):
ci_type_dict = CITypeCache.get(type_id).to_dict() ci_type_dict = CITypeCache.get(type_id).to_dict()

View File

@ -432,6 +432,13 @@ class Search(object):
return SearchFromDB(q, use_ci_filter=True, only_ids=True, count=100000).search() 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 @staticmethod
def _path2level(src_type_id, target_type_ids, path): def _path2level(src_type_id, target_type_ids, path):
if not src_type_id or not target_type_ids: 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] ci_ids = [j for i in paths for j in i]
response, _, _, _, _, _ = SearchFromDB("_type:({})".format(";".join(map(str, types))), response, _, _, _, _, _ = SearchFromDB("_type:({})".format(";".join(map(str, types))),
use_ci_filter=False,
ci_ids=list(map(int, ci_ids)), ci_ids=list(map(int, ci_ids)),
count=1000000).search() count=1000000).search()
id2ci = {str(i.get('_id')): i for i in response} id2ci = {str(i.get('_id')): i for i in response}
@ -539,6 +547,8 @@ class Search(object):
source_ids = self._get_src_ids(source) source_ids = self._get_src_ids(source)
graph, target_ids = self._build_graph(source_ids, level2type, target['type_ids'], acl) 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)) paths = self._find_paths(graph, source_ids, set(target_ids))
del graph del graph

View File

@ -8,7 +8,6 @@ from api.lib.cmdb.ci_type import CITypeManager
from api.lib.cmdb.ci_type import CITypeRelationManager from api.lib.cmdb.ci_type import CITypeRelationManager
from api.lib.cmdb.const import PermEnum from api.lib.cmdb.const import PermEnum
from api.lib.cmdb.const import ResourceTypeEnum 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.preference import PreferenceManager
from api.lib.cmdb.resp_format import ErrFormat from api.lib.cmdb.resp_format import ErrFormat
from api.lib.common_setting.decorator import perms_role_required 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 ACLManager
from api.lib.perm.acl.acl import has_perm_from_args 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 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 from api.resource import APIView
app_cli = CMDBApp() app_cli = CMDBApp()
@ -42,6 +41,19 @@ class GetParentsView(APIView):
return self.jsonify(parents=CITypeRelationManager.get_parents(child_id)) 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): class CITypeRelationView(APIView):
url_prefix = ("/ci_type_relations", "/ci_type_relations/<int:parent_id>/<int:child_id>") url_prefix = ("/ci_type_relations", "/ci_type_relations/<int:parent_id>/<int:child_id>")