from collections import defaultdict from django.db.models.signals import post_delete from django.db.models.signals import pre_save, post_save from django.dispatch import receiver from django.utils.translation import gettext_noop from accounts.backends import vault_client from audits.const import ActivityChoices from audits.signal_handlers import create_activities from common.decorators import merge_delay_run from common.utils import get_logger, i18n_fmt from .models import Account, AccountTemplate from .tasks.push_account import push_accounts_to_assets_task logger = get_logger(__name__) @receiver(pre_save, sender=Account) def on_account_pre_save(sender, instance, **kwargs): if instance.version == 0: instance.version = 1 else: history_account = instance.history.first() instance.version = history_account.version + 1 if history_account else 0 @merge_delay_run(ttl=5) def push_accounts_if_need(accounts=()): from .models import AccountTemplate template_accounts = defaultdict(list) for ac in accounts: # 再强调一次吧 if ac.source != 'template': continue template_accounts[ac.source_id].append(ac) for source_id, accounts in template_accounts.items(): template = AccountTemplate.objects.filter(id=source_id).first() if not template or not template.auto_push: continue logger.debug("Push accounts to source: %s", source_id) account_ids = [str(ac.id) for ac in accounts] task = push_accounts_to_assets_task.delay(account_ids, params=template.push_params) detail = i18n_fmt( gettext_noop('Push related accounts to assets: %s, by system'), len(account_ids) ) create_activities([str(template.id)], detail, task.id, ActivityChoices.task, template.org_id) logger.debug("Push accounts to source: %s, task: %s", source_id, task) def create_accounts_activities(account, action='create'): if action == 'create': detail = i18n_fmt(gettext_noop('Add account: %s'), str(account)) else: detail = i18n_fmt(gettext_noop('Delete account: %s'), str(account)) create_activities([account.asset_id], detail, None, ActivityChoices.operate_log, account.org_id) @receiver(post_save, sender=Account) def on_account_create_by_template(sender, instance, created=False, **kwargs): if not created or instance.source != 'template': return push_accounts_if_need(accounts=(instance,)) create_accounts_activities(instance, action='create') @receiver(post_delete, sender=Account) def on_account_delete(sender, instance, **kwargs): create_accounts_activities(instance, action='delete') class VaultSignalHandler(object): """ 处理 Vault 相关的信号 """ @staticmethod def save_to_vault(sender, instance, created, **kwargs): if created: vault_client.create(instance) else: vault_client.update(instance) @staticmethod def delete_to_vault(sender, instance, **kwargs): vault_client.delete(instance) for model in (Account, AccountTemplate, Account.history.model): post_save.connect(VaultSignalHandler.save_to_vault, sender=model) post_delete.connect(VaultSignalHandler.delete_to_vault, sender=model)