0

I created a script to execute an Ansible playbook file:

from StringIO import StringIO
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.module_utils.basic import AnsibleModule


def ansible_executor(playbook_path, user_extra_vars=()):

    loader = DataLoader()


    context.CLIARGS = ImmutableDict(tags={}, listtags=False, listtasks=False, listhosts=False, syntax=False,
                                    connection='ssh',
                                    module_path=None, forks=100, remote_user='root', 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,
                                    extra_vars=user_extra_vars)

    inventory = InventoryManager(loader=loader, sources=('/etc/ansible/hosts',))

    variable_manager = VariableManager(loader=loader, inventory=inventory, version_info=CLI.version_info(gitinfo=False))

    pbex = PlaybookExecutor(playbooks=[playbook_path], inventory=inventory, variable_manager=variable_manager,
                            loader=loader, passwords={})


    return pbex.run() == 0

I'm trying to log the playbook callback to my log file.

i saw a few threads talking about using the API CallbackModule but i haven't managed to successfully implement this. The Ansible documentation is lacking.

I found a workaround to save the output to veritable and send that to my log:

    old_stdout = sys.stdout
    result = StringIO()
    sys.stdout = result
    exit_code = pbex.run()
    sys.stdout = old_stdout
    log.info(result.getvalue())

but i know this isn't the correct way to go.

what am i missing with the callback module?

I know this API isn't sable and things are changing rapidly, is the a different solution?

Elad L.
  • 629
  • 1
  • 10
  • 25

1 Answers1

1

I don't know if my way is the right way, but anyway I will share:

I just inherit from ansible.plugins.callback.CallbackBase and implement log aggregator:

class ResultCallback(CallbackBase):
    def v2_runner_on_ok(self, result, **kwargs):
        host = result._host
        logger.info(json.dumps({host.name: result._result}, indent=4))

    def v2_runner_item_on_failed(self, result):
        host = result._host
        logger.error(json.dumps({host.name: result._result}, indent=4))

    def v2_runner_on_unreachable(self, result):
        host = result._host
        logger.error(json.dumps({host.name: result._result}, indent=4))   

This is simple printing results to standard python logger and this is an example. The callback has self-display and dump functions and you can format output separate for screen and for a log. You also can format output by using:

class ResultCallback(CallbackBase):
    def v2_runner_on_ok(self, result, **kwargs):
      text = "{0} success on host {1}".format(result._task.name, result._host)
      self._display.display(text, color=color, screen_only=True)
      self._display.display(self._dump_results(result._result), log_only=True)

I write this in python 3.6 and ansible 2.7 This software was run into docker container.

I hope these examples make sense.

ozlevka
  • 1,988
  • 16
  • 28
  • thanks for the answer. it was helpful but i'm having trouble in getting the output formatting to look like the original playbook display. currently i'm getting a long JSON with all the properties of the playbook, – Elad L. Oct 17 '19 at 07:44
  • 1
    Sorry, I was unclear. self._display.display(self._dump_results(result._result), log_only=True) function output is same as ansible-playbook. – ozlevka Oct 17 '19 at 07:55
  • its throwing this error when i use the display method: [WARNING]: Failure using method (v2_runner_on_ok) in callback plugin (): 'ResultCallback' object has no attribute '_display' – Elad L. Oct 17 '19 at 08:32
  • Sorry for the incomplete code. I provide examples only. You should create your ResultCallback well, I'm missing all inheritance rules as run super __init__ function. __init__ of a parent class provides _display member. ```https://github.com/ansible/ansible/blob/ba686154b98194de04a0c37970a3b997394ab7be/lib/ansible/plugins/callback/__init__.py#L65-L76```. Also you can read about inheritance in python here: https://www.geeksforgeeks.org/inheritance-in-python/ – ozlevka Oct 17 '19 at 09:49