diff --git a/cmdb-api/api/lib/cmdb/ci.py b/cmdb-api/api/lib/cmdb/ci.py index c2a2509..8c88f67 100644 --- a/cmdb-api/api/lib/cmdb/ci.py +++ b/cmdb-api/api/lib/cmdb/ci.py @@ -1086,6 +1086,31 @@ class CIRelationManager(object): for ci_id in ci_ids: cls.delete_2(parent_id, ci_id, ancestor_ids=ancestor_ids) + @classmethod + def build_by_attribute(cls, ci_dict): + type_id = ci_dict['_type'] + child_items = CITypeRelation.get_by(parent_id=type_id, only_query=True).filter( + CITypeRelation.parent_attr_id.isnot(None)) + for item in child_items: + parent_attr = AttributeCache.get(item.parent_attr_id) + child_attr = AttributeCache.get(item.child_attr_id) + attr_value = ci_dict.get(parent_attr.name) + value_table = TableMap(attr=child_attr).table + for child in value_table.get_by(attr_id=child_attr.id, value=attr_value, only_query=True).join( + CI, CI.id == value_table.ci_id).filter(CI.type_id == item.child_id): + CIRelationManager.add(ci_dict['_id'], child.ci_id) + + parent_items = CITypeRelation.get_by(child_id=type_id, only_query=True).filter( + CITypeRelation.child_attr_id.isnot(None)) + for item in parent_items: + parent_attr = AttributeCache.get(item.parent_attr_id) + child_attr = AttributeCache.get(item.child_attr_id) + attr_value = ci_dict.get(child_attr.name) + value_table = TableMap(attr=parent_attr).table + for parent in value_table.get_by(attr_id=parent_attr.id, value=attr_value, only_query=True).join( + CI, CI.id == value_table.ci_id).filter(CI.type_id == item.parent_id): + CIRelationManager.add(parent.ci_id, ci_dict['_id']) + class CITriggerManager(object): @staticmethod diff --git a/cmdb-api/api/lib/cmdb/ci_type.py b/cmdb-api/api/lib/cmdb/ci_type.py index 16a9e19..b43f22e 100644 --- a/cmdb-api/api/lib/cmdb/ci_type.py +++ b/cmdb-api/api/lib/cmdb/ci_type.py @@ -672,6 +672,10 @@ class CITypeAttributeManager(object): item = CITypeTrigger.get_by(type_id=_type_id, attr_id=attr_id, to_dict=False, first=True) item and item.soft_delete(commit=False) + for item in (CITypeRelation.get_by(parent_id=type_id, parent_attr_id=attr_id, to_dict=False) + + CITypeRelation.get_by(child_id=type_id, child_attr_id=attr_id, to_dict=False)): + item.soft_delete(commit=False) + db.session.commit() CITypeAttributeCache.clean(type_id, attr_id) @@ -813,7 +817,8 @@ class CITypeRelationManager(object): return "{} -> {}".format(first_name, second_name) @classmethod - def add(cls, parent, child, relation_type_id, constraint=ConstraintEnum.One2Many): + def add(cls, parent, child, relation_type_id, constraint=ConstraintEnum.One2Many, + parent_attr_id=None, child_attr_id=None): p = CITypeManager.check_is_existed(parent) c = CITypeManager.check_is_existed(child) @@ -828,24 +833,18 @@ class CITypeRelationManager(object): current_app.logger.warning(str(e)) return abort(400, ErrFormat.circular_dependency_error) - # if constraint == ConstraintEnum.Many2Many: - # other_c = CITypeRelation.get_by(parent_id=p.id, constraint=ConstraintEnum.Many2Many, - # to_dict=False, first=True) - # other_p = CITypeRelation.get_by(child_id=c.id, constraint=ConstraintEnum.Many2Many, - # to_dict=False, first=True) - # if other_c and other_c.child_id != c.id: - # return abort(400, ErrFormat.m2m_relation_constraint.format(p.name, other_c.child.name)) - # if other_p and other_p.parent_id != p.id: - # return abort(400, ErrFormat.m2m_relation_constraint.format(other_p.parent.name, c.name)) - existed = cls._get(p.id, c.id) if existed is not None: existed.update(relation_type_id=relation_type_id, - constraint=constraint) + constraint=constraint, + parent_attr_id=parent_attr_id, + child_attr_id=child_attr_id) else: existed = CITypeRelation.create(parent_id=p.id, child_id=c.id, relation_type_id=relation_type_id, + parent_attr_id=parent_attr_id, + child_attr_id=child_attr_id, constraint=constraint) if current_app.config.get("USE_ACL"): diff --git a/cmdb-api/api/models/cmdb.py b/cmdb-api/api/models/cmdb.py index a585eb3..193c94b 100644 --- a/cmdb-api/api/models/cmdb.py +++ b/cmdb-api/api/models/cmdb.py @@ -75,6 +75,9 @@ class CITypeRelation(Model): relation_type_id = db.Column(db.Integer, db.ForeignKey("c_relation_types.id"), nullable=False) constraint = db.Column(db.Enum(*ConstraintEnum.all()), default=ConstraintEnum.One2Many) + parent_attr_id = db.Column(db.Integer, db.ForeignKey("c_attributes.id")) + child_attr_id = db.Column(db.Integer, db.ForeignKey("c_attributes.id")) + parent = db.relationship("CIType", primaryjoin="CIType.id==CITypeRelation.parent_id") child = db.relationship("CIType", primaryjoin="CIType.id==CITypeRelation.child_id") relation_type = db.relationship("RelationType", backref="c_ci_type_relations.relation_type_id") diff --git a/cmdb-api/api/tasks/cmdb.py b/cmdb-api/api/tasks/cmdb.py index 16b4723..a5cc9bb 100644 --- a/cmdb-api/api/tasks/cmdb.py +++ b/cmdb-api/api/tasks/cmdb.py @@ -2,7 +2,6 @@ import json -import time import redis_lock from flask import current_app @@ -33,8 +32,7 @@ from api.models.cmdb import CITypeAttribute @reconnect_db def ci_cache(ci_id, operate_type, record_id): from api.lib.cmdb.ci import CITriggerManager - - time.sleep(0.01) + from api.lib.cmdb.ci import CIRelationManager m = api.lib.cmdb.ci.CIManager() ci_dict = m.get_ci_by_id_from_db(ci_id, need_children=False, use_master=False) @@ -52,13 +50,13 @@ def ci_cache(ci_id, operate_type, record_id): CITriggerManager.fire(operate_type, ci_dict, record_id) + ci_dict and CIRelationManager.build_by_attribute(ci_dict) + @celery.task(name="cmdb.batch_ci_cache", queue=CMDB_QUEUE) @flush_db @reconnect_db def batch_ci_cache(ci_ids, ): # only for attribute change index - time.sleep(1) - for ci_id in ci_ids: m = api.lib.cmdb.ci.CIManager() ci_dict = m.get_ci_by_id_from_db(ci_id, need_children=False, use_master=False) @@ -87,7 +85,6 @@ def ci_delete(ci_id): @celery.task(name="cmdb.delete_id_filter", queue=CMDB_QUEUE) @reconnect_db def delete_id_filter(ci_id): - CIFilterPermsCRUD().delete_id_filter_by_ci_id(ci_id) diff --git a/cmdb-api/api/views/cmdb/ci_type_relation.py b/cmdb-api/api/views/cmdb/ci_type_relation.py index 3e1dc87..3f1a72f 100644 --- a/cmdb-api/api/views/cmdb/ci_type_relation.py +++ b/cmdb-api/api/views/cmdb/ci_type_relation.py @@ -52,7 +52,10 @@ class CITypeRelationView(APIView): def post(self, parent_id, child_id): relation_type_id = request.values.get("relation_type_id") constraint = request.values.get("constraint") - ctr_id = CITypeRelationManager.add(parent_id, child_id, relation_type_id, constraint) + parent_attr_id = request.values.get("parent_attr_id") + child_attr_id = request.values.get("child_attr_id") + ctr_id = CITypeRelationManager.add(parent_id, child_id, relation_type_id, constraint, + parent_attr_id, child_attr_id) return self.jsonify(ctr_id=ctr_id)