From 33f6c5b25791d42f7d6e6c92c8a8f7bb21019ac5 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 22 Feb 2023 15:13:51 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20=E6=8E=A2=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/accounts/automations/base/manager.py | 46 -------------- .../automations/change_secret/manager.py | 8 ++- .../automations/push_account/manager.py | 3 +- .../verify_account/host/posix/main.yml | 6 +- .../automations/verify_account/manager.py | 55 ++++++++++++++++- apps/assets/automations/base/manager.py | 61 ++++++++----------- 6 files changed, 87 insertions(+), 92 deletions(-) diff --git a/apps/accounts/automations/base/manager.py b/apps/accounts/automations/base/manager.py index 6251c93a2..401304597 100644 --- a/apps/accounts/automations/base/manager.py +++ b/apps/accounts/automations/base/manager.py @@ -1,57 +1,11 @@ -from copy import deepcopy - from accounts.automations.methods import platform_automation_methods -from accounts.const import SecretType from assets.automations.base.manager import BasePlaybookManager from common.utils import get_logger logger = get_logger(__name__) -class VerifyHostCallbackMixin: - execution: callable - get_accounts: callable - host_account_mapper: dict - generate_public_key: callable - generate_private_key_path: callable - - def host_callback(self, host, asset=None, account=None, automation=None, path_dir=None, **kwargs): - host = super().host_callback( - host, asset=asset, account=account, - automation=automation, path_dir=path_dir, **kwargs - ) - if host.get('error'): - return host - - accounts = asset.accounts.all() - accounts = self.get_accounts(account, accounts) - inventory_hosts = [] - - for account in accounts: - h = deepcopy(host) - h['name'] += '(' + account.username + ')' - self.host_account_mapper[h['name']] = account - secret = account.secret - - private_key_path = None - if account.secret_type == SecretType.SSH_KEY: - private_key_path = self.generate_private_key_path(secret, path_dir) - secret = self.generate_public_key(secret) - - h['secret_type'] = account.secret_type - h['account'] = { - 'name': account.name, - 'username': account.username, - 'secret_type': account.secret_type, - 'secret': secret, - 'private_key_path': private_key_path - } - inventory_hosts.append(h) - return inventory_hosts - - class AccountBasePlaybookManager(BasePlaybookManager): - pass @property def platform_automation_methods(self): diff --git a/apps/accounts/automations/change_secret/manager.py b/apps/accounts/automations/change_secret/manager.py index a6c14fa23..fc4d53097 100644 --- a/apps/accounts/automations/change_secret/manager.py +++ b/apps/accounts/automations/change_secret/manager.py @@ -87,7 +87,8 @@ class ChangeSecretManager(AccountBasePlaybookManager): accounts = accounts.filter(secret_type=self.secret_type) if not accounts: - print('没有发现待改密账号: %s 用户名: %s 类型: %s' % (asset.name, account.username, self.secret_type)) + msg = '没有发现待改密账号: %s 用户名: %s 类型: %s' % (asset.name, account.username, self.secret_type) + print(msg) return [] method_attr = getattr(automation, self.method_type() + '_method') @@ -98,7 +99,8 @@ class ChangeSecretManager(AccountBasePlaybookManager): host['secret_type'] = self.secret_type if asset.type == HostTypes.WINDOWS and self.secret_type == SecretType.SSH_KEY: - print(f'Windows {asset} does not support ssh key push \n') + msg = f'Windows {asset} does not support ssh key push \n' + print(msg) return inventory_hosts for account in accounts: @@ -143,7 +145,7 @@ class ChangeSecretManager(AccountBasePlaybookManager): recorder.save() account = recorder.account if not account: - print("Account not found, deleted ?", recorder) + print("Account not found, deleted ?") return account.secret = recorder.new_secret account.save(update_fields=['secret']) diff --git a/apps/accounts/automations/push_account/manager.py b/apps/accounts/automations/push_account/manager.py index 42a53fcb1..6ea99ecdf 100644 --- a/apps/accounts/automations/push_account/manager.py +++ b/apps/accounts/automations/push_account/manager.py @@ -63,7 +63,8 @@ class PushAccountManager(ChangeSecretManager, AccountBasePlaybookManager): inventory_hosts = [] host['secret_type'] = self.secret_type if asset.type == HostTypes.WINDOWS and self.secret_type == SecretType.SSH_KEY: - print(f'Windows {asset} does not support ssh key push \n') + msg = f'Windows {asset} does not support ssh key push \n' + print(msg) return inventory_hosts for account in accounts: diff --git a/apps/accounts/automations/verify_account/host/posix/main.yml b/apps/accounts/automations/verify_account/host/posix/main.yml index 41ae1768d..b096f9d84 100644 --- a/apps/accounts/automations/verify_account/host/posix/main.yml +++ b/apps/accounts/automations/verify_account/host/posix/main.yml @@ -1,11 +1,11 @@ - hosts: demo gather_facts: no tasks: - - name: Verify account - ansible.builtin.ping: + - name: Verify account connectivity become: no + ansible.builtin.ping: vars: + ansible_become: no ansible_user: "{{ account.username }}" ansible_password: "{{ account.secret }}" ansible_ssh_private_key_file: "{{ account.private_key_path }}" - ansible_become: no diff --git a/apps/accounts/automations/verify_account/manager.py b/apps/accounts/automations/verify_account/manager.py index 2b6c831dc..3d07a95da 100644 --- a/apps/accounts/automations/verify_account/manager.py +++ b/apps/accounts/automations/verify_account/manager.py @@ -1,18 +1,67 @@ +import os +from copy import deepcopy + from django.db.models import QuerySet -from accounts.const import AutomationTypes, Connectivity +from accounts.const import AutomationTypes, Connectivity, SecretType from common.utils import get_logger -from ..base.manager import VerifyHostCallbackMixin, AccountBasePlaybookManager +from ..base.manager import AccountBasePlaybookManager logger = get_logger(__name__) -class VerifyAccountManager(VerifyHostCallbackMixin, AccountBasePlaybookManager): +class VerifyAccountManager(AccountBasePlaybookManager): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.host_account_mapper = {} + 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 + + def host_callback(self, host, asset=None, account=None, automation=None, path_dir=None, **kwargs): + host = super().host_callback( + host, asset=asset, account=account, + automation=automation, path_dir=path_dir, **kwargs + ) + if host.get('error'): + return host + + # host['ssh_args'] = '-o ControlMaster=no -o ControlPersist=no' + accounts = asset.accounts.all() + accounts = self.get_accounts(account, accounts) + inventory_hosts = [] + + for account in accounts: + h = deepcopy(host) + h['name'] += '(' + account.username + ')' + self.host_account_mapper[h['name']] = account + secret = account.secret + + private_key_path = None + if account.secret_type == SecretType.SSH_KEY: + private_key_path = self.generate_private_key_path(secret, path_dir) + secret = self.generate_public_key(secret) + + h['secret_type'] = account.secret_type + h['account'] = { + 'name': account.name, + 'username': account.username, + 'secret_type': account.secret_type, + 'secret': secret, + 'private_key_path': private_key_path + } + inventory_hosts.append(h) + # print("Host: ") + # print(self.json_dumps(inventory_hosts)) + return inventory_hosts + @classmethod def method_type(cls): return AutomationTypes.verify_account diff --git a/apps/assets/automations/base/manager.py b/apps/assets/automations/base/manager.py index 02f84dc22..98c1afb9d 100644 --- a/apps/assets/automations/base/manager.py +++ b/apps/assets/automations/base/manager.py @@ -1,12 +1,11 @@ import json import os import shutil -import yaml - from collections import defaultdict from hashlib import md5 from socket import gethostname +import yaml from django.conf import settings from django.utils import timezone from django.utils.translation import gettext as _ @@ -55,8 +54,7 @@ class BasePlaybookManager: def get_assets_group_by_platform(self): return self.execution.all_assets_group_by_platform() - @lazyproperty - def runtime_dir(self): + def prepare_runtime_dir(self): ansible_dir = settings.ANSIBLE_DIR task_name = self.execution.snapshot['name'] dir_name = '{}_{}'.format(task_name.replace(' ', '_'), self.execution.id) @@ -66,8 +64,14 @@ class BasePlaybookManager: ) if not os.path.exists(path): os.makedirs(path, exist_ok=True, mode=0o755) + return path + + @lazyproperty + def runtime_dir(self): + path = self.prepare_runtime_dir() if settings.DEBUG_DEV: - print(f'Ansible runtime dir: {path}') + msg = 'Ansible runtime dir: {}'.format(path) + print(msg) return path @staticmethod @@ -158,7 +162,8 @@ class BasePlaybookManager: def get_runners(self): assets_group_by_platform = self.get_assets_group_by_platform() if settings.DEBUG_DEV: - print("assets_group_by_platform: {}".format(assets_group_by_platform)) + msg = 'Assets group by platform: {}'.format(dict(assets_group_by_platform)) + print(msg) runners = [] for platform, assets in assets_group_by_platform.items(): assets_bulked = [assets[i:i + self.bulk_size] for i in range(0, len(assets), self.bulk_size)] @@ -199,8 +204,7 @@ class BasePlaybookManager: if state == 'ok': self.on_host_success(host, result) elif state == 'skipped': - # TODO - print('skipped: ', hosts) + pass else: error = hosts.get(host) self.on_host_error(host, error, result) @@ -214,10 +218,14 @@ class BasePlaybookManager: d = json.load(f) return d + @staticmethod + def json_dumps(data): + return json.dumps(data, indent=4, sort_keys=True) + @staticmethod def json_to_file(path, data): with open(path, 'w') as f: - json.dump(data, f) + json.dump(data, f, indent=4, sort_keys=True) def local_gateway_prepare(self, runner): info = self.file_to_json(runner.inventory) @@ -241,47 +249,27 @@ class BasePlaybookManager: def local_gateway_clean(self, runner): servers = self.gateway_servers.get(runner.id, []) - try: - for s in servers: - print('Server down: %s' % s) + for s in servers: + try: s.stop() - except Exception: - pass + except Exception: + pass def before_runner_start(self, runner): self.local_gateway_prepare(runner) def after_runner_end(self, runner): - self.delete_sensitive_data(runner.inventory) self.local_gateway_clean(runner) - def delete_sensitive_data(self, path): + def delete_runtime_dir(self): if settings.DEBUG_DEV: return - - d = self.file_to_json(path) - - def delete_keys(d, keys_to_delete): - """ - 递归函数:删除嵌套字典中的指定键 - """ - if not isinstance(d, dict): - return d - keys = list(d.keys()) - for key in keys: - if key in keys_to_delete: - del d[key] - else: - delete_keys(d[key], keys_to_delete) - return d - - d = delete_keys(d, ['secret', 'ansible_password']) - self.json_to_file(path, d) + shutil.rmtree(self.runtime_dir) def run(self, *args, **kwargs): runners = self.get_runners() if len(runners) > 1: - print("### 分批次执行开始任务, 总共 {}\n".format(len(runners))) + print("### 分次执行任务, 总共 {}\n".format(len(runners))) elif len(runners) == 1: print(">>> 开始执行任务\n") else: @@ -303,3 +291,4 @@ class BasePlaybookManager: self.execution.status = 'success' self.execution.date_finished = timezone.now() self.execution.save() + self.delete_runtime_dir()