From bbd74b02a60818ff0cb973001e7e576788089195 Mon Sep 17 00:00:00 2001 From: lovvvve Date: Thu, 17 Aug 2023 09:54:23 +0000 Subject: [PATCH] =?UTF-8?q?ci=20=E6=94=AF=E6=8C=81=20=E8=BD=AF=E5=88=A0?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmdb-api/api/lib/cmdb/ci.py | 47 ++++++++++++++++++++++++---------- cmdb-api/api/lib/cmdb/const.py | 1 + cmdb-api/api/lib/database.py | 6 ++--- cmdb-api/api/tasks/cmdb.py | 16 ++++++++++++ cmdb-api/api/views/cmdb/ci.py | 21 +++++++++++++-- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/cmdb-api/api/lib/cmdb/ci.py b/cmdb-api/api/lib/cmdb/ci.py index b70f4d2..0c36283 100644 --- a/cmdb-api/api/lib/cmdb/ci.py +++ b/cmdb-api/api/lib/cmdb/ci.py @@ -233,9 +233,12 @@ class CIManager(object): return CI.get_by_id(unique.ci_id) @staticmethod - def _delete_ci_by_id(ci_id): + def _delete_ci_by_id(ci_id, soft_delete=False): ci = CI.get_by_id(ci_id) - ci.delete() # TODO: soft delete + if soft_delete: + ci.soft_delete() + else: + ci.delete() @staticmethod def _valid_unique_constraint(type_id, ci_dict, ci_id=None): @@ -442,8 +445,8 @@ class CIManager(object): ci_cache.apply_async([ci_id], queue=CMDB_QUEUE) @classmethod - def delete(cls, ci_id): - ci = CI.get_by_id(ci_id) or abort(404, ErrFormat.ci_not_found.format("id={}".format(ci_id))) + def delete(cls, ci_id, soft_delete=False): + ci = CI.get_by_id(ci_id, not soft_delete) or abort(404, ErrFormat.ci_not_found.format("id={}".format(ci_id))) cls._valid_ci_for_no_read(ci) @@ -454,20 +457,32 @@ class CIManager(object): attr_names = set([AttributeCache.get(attr.attr_id).name for attr in attrs]) for attr_name in attr_names: value_table = TableMap(attr_name=attr_name).table - for item in value_table.get_by(ci_id=ci_id, to_dict=False): + for item in value_table.get_by(ci_id=ci_id, to_dict=False, deleted=not soft_delete): + if soft_delete: + item.soft_delete() + else: + item.delete() + + for item in CIRelation.get_by(first_ci_id=ci_id, to_dict=False, deleted=not soft_delete): + ci_relation_delete.apply_async(args=(item.first_ci_id, item.second_ci_id), queue=CMDB_QUEUE) + if soft_delete: + item.soft_delete() + else: item.delete() - for item in CIRelation.get_by(first_ci_id=ci_id, to_dict=False): + for item in CIRelation.get_by(second_ci_id=ci_id, to_dict=False, deleted=not soft_delete): ci_relation_delete.apply_async(args=(item.first_ci_id, item.second_ci_id), queue=CMDB_QUEUE) - item.delete() + if soft_delete: + item.soft_delete() + else: + item.delete() - for item in CIRelation.get_by(second_ci_id=ci_id, to_dict=False): - ci_relation_delete.apply_async(args=(item.first_ci_id, item.second_ci_id), queue=CMDB_QUEUE) - item.delete() - - ci.delete() # TODO: soft delete - - AttributeHistoryManger.add(None, ci_id, [(None, OperateType.DELETE, ci_dict, None)], ci.type_id) + if soft_delete: + ci.soft_delete() + AttributeHistoryManger.add(None, ci_id, [(None, OperateType.SOFT_DELETE, ci_dict, None)], ci.type_id) + else: + ci.delete() + AttributeHistoryManger.add(None, ci_id, [(None, OperateType.DELETE, ci_dict, None)], ci.type_id) ci_delete.apply_async([ci.id], queue=CMDB_QUEUE) @@ -651,6 +666,10 @@ class CIManager(object): current_app.logger.warning("cache not hit...............") return cls._get_cis_from_db(ci_ids, ret_key, fields, value_tables, excludes=excludes) + @classmethod + def get_soft_delete_ids(cls): + return [ci.get("id") for ci in CI.get_by(deleted=True)] + class CIRelationManager(object): """ diff --git a/cmdb-api/api/lib/cmdb/const.py b/cmdb-api/api/lib/cmdb/const.py index 118e053..4bfc725 100644 --- a/cmdb-api/api/lib/cmdb/const.py +++ b/cmdb-api/api/lib/cmdb/const.py @@ -36,6 +36,7 @@ class OperateType(BaseEnum): ADD = "0" DELETE = "1" UPDATE = "2" + SOFT_DELETE = "3" class CITypeOperateType(BaseEnum): diff --git a/cmdb-api/api/lib/database.py b/cmdb-api/api/lib/database.py index dfe1fb1..564e255 100644 --- a/cmdb-api/api/lib/database.py +++ b/cmdb-api/api/lib/database.py @@ -20,7 +20,7 @@ class FormatMixin(object): res.pop('secret', None) return res - + @classmethod def from_dict(cls, **kwargs): from sqlalchemy.sql.sqltypes import Time, Date, DateTime @@ -86,11 +86,11 @@ class CRUDMixin(FormatMixin): self.save(flush=flush, commit=commit) @classmethod - def get_by_id(cls, _id): + def get_by_id(cls, _id, with_soft_deleted=False): if any((isinstance(_id, six.string_types) and _id.isdigit(), isinstance(_id, (six.integer_types, float))), ): obj = getattr(cls, "query").get(int(_id)) - if obj and not obj.deleted: + if obj and (with_soft_deleted or not obj.deleted): return obj @classmethod diff --git a/cmdb-api/api/tasks/cmdb.py b/cmdb-api/api/tasks/cmdb.py index 4d120ed..39122d3 100644 --- a/cmdb-api/api/tasks/cmdb.py +++ b/cmdb-api/api/tasks/cmdb.py @@ -156,3 +156,19 @@ def trigger_notify(notify, ci_id): for i in notify['mail_to'] if i], subject, body) except Exception as e: current_app.logger.error("Send mail failed: {0}".format(str(e))) + + +@celery.task(name='cmdb.delete_soft_deleted_ci', queue=CMDB_QUEUE) +def delete_soft_deleted_ci(ci_id): + current_app.logger.info("delete_soft_deleted_ci: {}".format(ci_id)) + + from api.app import create_app + from flask_login import login_user + from api.lib.perm.acl.cache import UserCache + + app = create_app() + app.test_request_context().push() + login_user(UserCache.get('worker')) + + manager = api.lib.cmdb.ci.CIManager() + manager.delete(ci_id) diff --git a/cmdb-api/api/views/cmdb/ci.py b/cmdb-api/api/views/cmdb/ci.py index cb285b5..cd08441 100644 --- a/cmdb-api/api/views/cmdb/ci.py +++ b/cmdb-api/api/views/cmdb/ci.py @@ -1,4 +1,4 @@ -# -*- coding:utf-8 -*- +# -*- coding:utf-8 -*- import time @@ -10,7 +10,7 @@ from flask import request from api.lib.cmdb.cache import CITypeCache from api.lib.cmdb.ci import CIManager from api.lib.cmdb.ci import CIRelationManager -from api.lib.cmdb.const import ExistPolicy +from api.lib.cmdb.const import ExistPolicy, CMDB_QUEUE from api.lib.cmdb.const import ResourceTypeEnum, PermEnum from api.lib.cmdb.const import RetKey from api.lib.cmdb.perms import has_perm_for_ci @@ -240,3 +240,20 @@ class CIAutoDiscoveryStatisticsView(APIView): def get(self): return self.jsonify(CIManager.get_ad_statistics()) + + +class SoftDeleteCis(APIView): + url_prefix = ("/ci/soft_deleted/cis",) + + def get(self): + manager = CIManager() + ids = manager.get_soft_delete_ids() + return self.jsonify({"count": len(ids), "ids": ids}) + + def delete(self): + from api.tasks.cmdb import delete_soft_deleted_ci + manager = CIManager() + ids = manager.get_soft_delete_ids() + for _id in ids: + delete_soft_deleted_ci.apply_async([_id], queue=CMDB_QUEUE) + return self.jsonify(message="add {} ci to celery".format(len(ids)))