perf: 重构 playbook base runner

pull/8970/head
ibuler 2022-10-13 20:28:18 +08:00
parent 52fb55e806
commit 0a65b9de8e
2 changed files with 56 additions and 80 deletions

View File

@ -1,7 +1,6 @@
import os import os
import shutil import shutil
import yaml import yaml
from copy import deepcopy
from collections import defaultdict from collections import defaultdict
from django.conf import settings from django.conf import settings
@ -42,33 +41,23 @@ class BasePlaybookManager:
def method_type(cls): def method_type(cls):
raise NotImplementedError raise NotImplementedError
def get_assets_group_by_platform(self):
return self.automation.all_assets_group_by_platform()
@property @property
def runtime_dir(self): def runtime_dir(self):
ansible_dir = settings.ANSIBLE_DIR ansible_dir = settings.ANSIBLE_DIR
dir_name = '{}_{}'.format(self.automation.name.replace(' ', '_'), self.execution.id)
path = os.path.join( path = os.path.join(
ansible_dir, self.automation.type, ansible_dir, 'automations', self.automation.type,
self.automation.name.replace(' ', '_'), dir_name, timezone.now().strftime('%Y%m%d_%H%M%S')
timezone.now().strftime('%Y%m%d_%H%M%S')
) )
if not os.path.exists(path):
os.makedirs(path, exist_ok=True, mode=0o755)
return path return path
@property
def inventory_path(self):
return os.path.join(self.runtime_dir, 'inventory', 'hosts.json')
@property
def playbook_path(self):
return os.path.join(self.runtime_dir, 'project', 'main.yml')
def generate(self):
self.prepare_playbook_dir()
self.generate_inventory()
self.generate_playbook()
def prepare_playbook_dir(self): def prepare_playbook_dir(self):
inventory_dir = os.path.dirname(self.inventory_path) for d in [self.runtime_dir]:
playbook_dir = os.path.dirname(self.playbook_path)
for d in [inventory_dir, playbook_dir]:
if not os.path.exists(d): if not os.path.exists(d):
os.makedirs(d, exist_ok=True, mode=0o755) os.makedirs(d, exist_ok=True, mode=0o755)
@ -82,67 +71,51 @@ class BasePlaybookManager:
getattr(automation, method_attr) in self.method_id_meta_mapper getattr(automation, method_attr) in self.method_id_meta_mapper
if not method_enabled: if not method_enabled:
host['error'] = _('Change password disabled') host['error'] = _('{} disabled'.format(self.__class__.method_type()))
return host
return host return host
self.method_hosts_mapper[getattr(automation, method_attr)].append(host['name']) def generate_inventory(self, platformed_assets, inventory_path):
return host
def generate_inventory(self):
inventory = JMSInventory( inventory = JMSInventory(
assets=self.automation.get_all_assets(), assets=platformed_assets,
account_policy=self.ansible_account_policy, account_policy=self.ansible_account_policy,
host_callback=self.host_callback host_callback=self.host_callback
) )
inventory.write_to_file(self.inventory_path) inventory.write_to_file(inventory_path)
logger.debug("Generate inventory done: {}".format(self.inventory_path))
def generate_playbook(self): def generate_playbook(self, platformed_assets, platform, sub_playbook_dir):
main_playbook = [] method_id = getattr(platform.automation, '{}_method'.format(self.__class__.method_type()))
for method_id, host_names in self.method_hosts_mapper.items():
method = self.method_id_meta_mapper.get(method_id) method = self.method_id_meta_mapper.get(method_id)
if not method: if not method:
logger.error("Method not found: {}".format(method_id)) logger.error("Method not found: {}".format(method_id))
continue return method
method_playbook_dir_path = method['dir'] method_playbook_dir_path = method['dir']
method_playbook_dir_name = os.path.basename(method_playbook_dir_path) sub_playbook_path = os.path.join(sub_playbook_dir, 'project', 'main.yml')
sub_playbook_dir = os.path.join(os.path.dirname(self.playbook_path), method_playbook_dir_name) shutil.copytree(method_playbook_dir_path, os.path.dirname(sub_playbook_path))
sub_playbook_path = os.path.join(sub_playbook_dir, 'main.yml')
shutil.copytree(method_playbook_dir_path, sub_playbook_dir)
with open(sub_playbook_path, 'r') as f: with open(sub_playbook_path, 'r') as f:
host_playbook_play = yaml.safe_load(f) plays = yaml.safe_load(f)
for play in plays:
play['hosts'] = 'all'
if isinstance(host_playbook_play, list): with open(sub_playbook_path, 'w') as f:
host_playbook_play = host_playbook_play[0]
hosts_bulked = [host_names[i:i+self.bulk_size] for i in range(0, len(host_names), self.bulk_size)]
for i, hosts in enumerate(hosts_bulked):
plays = []
play = deepcopy(host_playbook_play)
play['hosts'] = ':'.join(hosts)
plays.append(play)
playbook_path = os.path.join(sub_playbook_dir, 'part_{}.yml'.format(i))
with open(playbook_path, 'w') as f:
yaml.safe_dump(plays, f) yaml.safe_dump(plays, f)
self.playbooks.append([playbook_path, hosts]) return sub_playbook_path
main_playbook.append({
'name': method['name'] + ' for part {}'.format(i),
'import_playbook': os.path.join(method_playbook_dir_name, 'part_{}.yml'.format(i))
})
with open(self.playbook_path, 'w') as f:
yaml.safe_dump(main_playbook, f)
logger.debug("Generate playbook done: " + self.playbook_path)
def get_runners(self): def get_runners(self):
runners = [] runners = []
for playbook_path in self.playbooks: for platform, assets in self.get_assets_group_by_platform().items():
assets_bulked = [assets[i:i+self.bulk_size] for i in range(0, len(assets), self.bulk_size)]
for i, _assets in enumerate(assets_bulked, start=1):
sub_dir = '{}_{}'.format(platform.name, i)
playbook_dir = os.path.join(self.runtime_dir, sub_dir)
inventory_path = os.path.join(self.runtime_dir, sub_dir, 'hosts.json')
self.generate_inventory(_assets, inventory_path)
playbook_path = self.generate_playbook(_assets, platform, playbook_dir)
runer = PlaybookRunner( runer = PlaybookRunner(
self.inventory_path, inventory_path,
playbook_path, playbook_path,
self.runtime_dir, self.runtime_dir,
callback=PlaybookCallback(), callback=PlaybookCallback(),
@ -150,17 +123,18 @@ class BasePlaybookManager:
runners.append(runer) runners.append(runer)
return runners return runners
def on_runner_done(self, runner, cb): def on_runner_success(self, runner, cb):
raise NotImplementedError raise NotImplementedError
def on_runner_failed(self, runner, e): def on_runner_failed(self, runner, e):
print("Runner failed: {} {}".format(e, self)) print("Runner failed: {} {}".format(e, self))
def before_runner_start(self, runner): def before_runner_start(self, runner):
pass print("Start run task: ")
print(" inventory: {}".format(runner.inventory))
print(" playbook: {}".format(runner.playbook))
def run(self, **kwargs): def run(self, **kwargs):
self.generate()
runners = self.get_runners() runners = self.get_runners()
if len(runners) > 1: if len(runners) > 1:
print("### 分批次执行开始任务, 总共 {}\n".format(len(runners))) print("### 分批次执行开始任务, 总共 {}\n".format(len(runners)))
@ -173,7 +147,7 @@ class BasePlaybookManager:
self.before_runner_start(runner) self.before_runner_start(runner)
try: try:
cb = runner.run(**kwargs) cb = runner.run(**kwargs)
self.on_runner_done(runner, cb) self.on_runner_success(runner, cb)
except Exception as e: except Exception as e:
self.on_runner_failed(runner, e) self.on_runner_failed(runner, e)
print('\n\n') print('\n')

View File

@ -121,8 +121,10 @@ class ChangeSecretManager(BasePlaybookManager):
ChangeSecretRecord.objects.bulk_create(records) ChangeSecretRecord.objects.bulk_create(records)
return inventory_hosts return inventory_hosts
def on_runner_done(self, runner, cb): def on_runner_success(self, runner, cb):
summary = runner.summary summary = cb.summary
print("Summary: ")
print(summary)
def on_runner_failed(self, runner, e): def on_runner_failed(self, runner, e):
pass pass