import os from collections import defaultdict from copy import deepcopy from django.db.models import QuerySet from accounts.const import AutomationTypes from accounts.models import Account, GatheredAccount, AccountRisk from common.const import ConfirmOrIgnore from common.utils import get_logger from ..base.manager import AccountBasePlaybookManager logger = get_logger(__name__) class RemoveAccountManager(AccountBasePlaybookManager): super_accounts = ["root", "administrator"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.host_account_mapper = dict() self.host_accounts = defaultdict(list) snapshot_account = self.execution.snapshot.get("accounts", []) self.snapshot_asset_account_map = defaultdict(list) for account in snapshot_account: self.snapshot_asset_account_map[str(account["asset"])].append(account) # 给 handler 使用 self.delete = self.execution.snapshot.get("delete", "both") self.confirm_risk = self.execution.snapshot.get("risk", "") def prepare_runtime_dir(self): path = super().prepare_runtime_dir() ansible_config_path = os.path.join(path, "ansible.cfg") with open(ansible_config_path, "w") as f: f.write("[ssh_connection]\n") f.write("ssh_args = -o ControlMaster=no -o ControlPersist=no\n") return path @classmethod def method_type(cls): return AutomationTypes.remove_account def host_callback( self, host, asset=None, account=None, automation=None, path_dir=None, **kwargs ): if host.get("error"): return host inventory_hosts = [] accounts_to_remove = self.snapshot_asset_account_map.get(str(asset.id), []) for account in accounts_to_remove: username = account.get("username") if not username or username.lower() in self.super_accounts: print("Super account can not be remove: ", username) continue h = deepcopy(host) h["name"] += "(" + username + ")" self.host_account_mapper[h["name"]] = account h["account"] = {"username": username} inventory_hosts.append(h) return inventory_hosts def on_host_success(self, host, result): super().on_host_success(host, result) account = self.host_account_mapper.get(host) if not account: return try: if self.delete == "both": Account.objects.filter( asset_id=account["asset"], username=account["username"] ).delete() if self.confirm_risk: AccountRisk.objects.filter( asset_id=account["asset"], username=account["username"], risk__in=[self.confirm_risk], ).update(status=ConfirmOrIgnore.confirmed) GatheredAccount.objects.filter( asset_id=account["asset"], username=account["username"] ).delete() except Exception as e: logger.error( f"Failed to delete account {account['username']} on asset {account['asset']}: {e}" )