from ansible import context
from ansible.cli import CLI
from ansible.module_utils.common.collections import ImmutableDict
from ansible.executor.playbook_executor import PlaybookExecutor
from ansible.parsing.dataloader import DataLoader
from ansible.inventory.manager import InventoryManager
from ansible.vars.manager import VariableManager
from ansible.plugins.callback import CallbackBase
class PlaybookResultCallBack(CallbackBase):
"""
Custom callback model for handlering the output data of
execute playbook file,
Base on the build-in callback plugins of ansible which named `json`.
"""
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'stdout'
CALLBACK_NAME = 'Dict'
def __init__(self, display=None):
super(PlaybookResultCallBack, self).__init__(display)
self.results = []
self.output = ""
self.item_results = {} # {"host": []}
def _new_play(self, play):
return {
'play': {
'name': play.name,
'id': str(play._uuid)
},
'tasks': []
}
def _new_task(self, task):
return {
'task': {
'name': task.get_name(),
},
'hosts': {}
}
def v2_playbook_on_no_hosts_matched(self):
self.output = "skipping: No match hosts."
def v2_playbook_on_no_hosts_remaining(self):
pass
def v2_playbook_on_task_start(self, task, is_conditional):
self.results[-1]['tasks'].append(self._new_task(task))
def v2_playbook_on_play_start(self, play):
self.results.append(self._new_play(play))
def v2_playbook_on_stats(self, stats):
hosts = sorted(stats.processed.keys())
summary = {}
for h in hosts:
s = stats.summarize(h)
summary[h] = s
if self.output:
pass
else:
self.output = {
'plays': self.results,
'stats': summary
}
def gather_result(self, res):
if res._task.loop and "results" in res._result and res._host.name in self.item_results:
res._result.update({"results": self.item_results[res._host.name]})
del self.item_results[res._host.name]
self.results[-1]['tasks'][-1]['hosts'][res._host.name] = res._result
def v2_runner_on_ok(self, res, **kwargs):
if "ansible_facts" in res._result:
del res._result["ansible_facts"]
self.gather_result(res)
def v2_runner_on_failed(self, res, **kwargs):
self.gather_result(res)
def v2_runner_on_unreachable(self, res, **kwargs):
self.gather_result(res)
def v2_runner_on_skipped(self, res, **kwargs):
self.gather_result(res)
def gather_item_result(self, res):
self.item_results.setdefault(res._host.name, []).append(res._result)
def v2_runner_item_on_ok(self, res):
self.gather_item_result(res)
def v2_runner_item_on_failed(self, res):
self.gather_item_result(res)
def v2_runner_item_on_skipped(self, res):
self.gather_item_result(res)
loader = DataLoader()
results_callback = PlaybookResultCallBack()
context.CLIARGS = ImmutableDict(tags={}, listtags=False, listtasks=False, listhosts=False, syntax=False, connection='ssh',
module_path=None, forks=100, remote_user='xxx', private_key_file=None,
ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=True,
become_method='sudo', become_user='root', verbosity=True, check=False, start_at_task=None)
# Inventory file
inventory_full_path = os.path.join(SOME_BASE, "inventories", inventory_file_name)
inventory = InventoryManager(loader=loader, sources=(inventory_full_path,))
variable_manager = VariableManager(loader=loader, inventory=inventory, version_info=CLI.version_info(gitinfo=False))
print(f"Using playbook {playbook_name}")
pbex = PlaybookExecutor(playbooks=[playbook_name], inventory=inventory, variable_manager=variable_manager, loader=loader, passwords={})
pbex._tqm._stdout_callback = results_callback
# Run the playbook
results_raw = pbex.run()
# Get results from results_callback.output['stats'] dictionary