如何在Python代码中调用Ansible 2.0 API时屏蔽playbook输出?
嘿,这个问题我熟!Ansible 2.0 API默认确实会把playbook的执行过程一股脑打出来,要屏蔽这些输出的话,有几个靠谱的办法,你可以根据情况选:
解决Python调用Ansible 2.0 API屏蔽执行过程输出的方法
方法1:自定义回调类并禁用默认输出
你已经用了自定义的ResultsCollector回调,但可能默认的输出回调还在偷偷生效。可以重载回调类的方法,只收集结果不打印,同时确保Ansible只加载你的自定义回调:
首先完善你的自定义回调类:
from ansible.plugins.callback import CallbackBase class ResultsCollector(CallbackBase): def __init__(self, *args, **kwargs): super(ResultsCollector, self).__init__(*args, **kwargs) self.results = [] # 重载所有可能产生输出的方法,只收集结果不打印 def v2_runner_on_ok(self, result, **kwargs): self.results.append(result._result) def v2_runner_on_failed(self, result, **kwargs): self.results.append(result._result) def v2_runner_on_unreachable(self, result, **kwargs): self.results.append(result._result) # 其他如v2_playbook_on_start、v2_playbook_on_task_start等方法,留空或只收集数据即可
然后在run_playbook函数里,指定使用自定义回调并禁用默认输出:
from ansible.executor.playbook_executor import PlaybookExecutor from ansible.utils.display import Display def run_playbook(playbook, inventory, package, var_file_path, forks): callback = ResultsCollector() variable_manager = VariableManager() loader = DataLoader() inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=inventory) playbook_path = playbook if not os.path.exists(playbook_path): print "Playbook文件不存在!" return # 设置选项,把verbosity调到0减少输出 options = Options( forks=forks, verbosity=0, connection='ssh' ) pbex = PlaybookExecutor( playbooks=[playbook_path], inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords={} ) # 替换默认的输出回调为自定义的 pbex._tqm._stdout_callback = callback # 同时关闭Display类的输出 Display().verbosity = 0 result = pbex.run() return callback.results
方法2:临时重定向标准输出/错误
如果有些输出是Ansible底层直接打印到控制台的,没法通过回调控制,可以临时把stdout和stderr重定向到空设备:
import os import sys def run_playbook(playbook, inventory, package, var_file_path, forks): # 保存原来的输出流 original_stdout = sys.stdout original_stderr = sys.stderr # 重定向到空设备(Linux/macOS用/dev/null,Windows替换为'nul') dev_null = open(os.devnull, 'w') sys.stdout = dev_null sys.stderr = dev_null try: # 这里放你原来的playbook执行代码 callback = ResultsCollector() variable_manager = VariableManager() loader = DataLoader() inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=inventory) playbook_path = playbook if not os.path.exists(playbook_path): print "Playbook文件不存在!" return pbex = PlaybookExecutor( playbooks=[playbook_path], inventory=inventory, variable_manager=variable_manager, loader=loader, options=Options(forks=forks, verbosity=0), passwords={} ) pbex._tqm._stdout_callback = callback result = pbex.run() return callback.results finally: # 恢复原来的输出流 sys.stdout = original_stdout sys.stderr = original_stderr dev_null.close()
方法3:调整Ansible日志级别
通过环境变量把Ansible的日志级别调高到ERROR,这样只有错误信息会输出,执行过程的INFO级日志会被屏蔽:
import os def run_playbook(playbook, inventory, package, var_file_path, forks): # 设置环境变量,将日志级别设为ERROR os.environ['ANSIBLE_LOG_LEVEL'] = 'ERROR' # 后续的playbook执行代码和原来一致即可 callback = ResultsCollector() variable_manager = VariableManager() loader = DataLoader() inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=inventory) # ...其余代码不变
其中方法1是最推荐的,它从回调层面精准控制输出;方法2是兜底方案,适合处理那些无法通过回调拦截的输出;方法3则能快速减少Ansible本身的日志量。
内容的提问来源于stack exchange,提问作者Jitu
相关产品推荐
相关产品推荐

