Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the Ansible Python API, how can I get access to task level outputs in my code?

I use a playbook runner like so:

stats = callbacks.AggregateStats()                                           
playbook_cb = callbacks.PlaybookCallbacks(verbose=1)           
runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=1)                                 

pb = ansible.playbook.PlayBook(
... # basic info
)                                                                          
results = pb.run()

The results variable contains output like the following:

{"status": 1, "result": {"127.0.0.1": {"unreachable": 0, "skipped": 0, "ok": 3, "changed": 2, "failures": 0}}}

Which is fine. But I also need the task level output like the dict shown below:

changed: [127.0.0.1] => {"changed": true, "name": "apache2", "state": "started"}

I tried changing the verbosity, but that was not what I wanted.

After digging around I managed to get the output to a log file like so:

from ansible import constants as C
C.DEFAULT_LOG_PATH = 'project.log'
reload(callbacks)

But I need access to it in my code.

like image 438
Tom Sawyyer Avatar asked Sep 29 '22 03:09

Tom Sawyyer


People also ask

Does Ansible use API?

You can use the Ansible Python API to control nodes, you can extend Ansible to respond to various Python events, you can write plugins, and you can plug in inventory data from external data sources. This document gives a basic overview and examples of the Ansible execution and playbook API.

How do I keep secret data on my playbook Ansible?

How do I keep secret data in my playbook? ¶ If you would like to keep secret data in your Ansible content and still share it publicly or keep things in source control, see Vault. This can be used to keep verbose output but hide sensitive information from others who would otherwise like to be able to see the output.

How does Ansible use Python?

While you can write Ansible modules in any language, most Ansible modules are written in Python, including the ones central to letting Ansible work. By default, Ansible assumes it can find a /usr/bin/python on your remote system that is either Python2, version 2.6 or higher or Python3, 3.5 or higher.

Does Ansible require python on target?

By default Ansible modules require python to be present in the target machines, since they are all written in python.


1 Answers

You probably can't get exactly the json format you wanted, but you can get the same information by extending the callback classes and write your own handlers to events that you are interested.

Also make sure that you give the classes to the Playbook instance like this:

pb = ansible.playbook.PlayBook(
    ... # basic info
    callbacks= playbook_cb,
    runner_callbacks=runner_cb
)        

Links:

  • Methods for Runner Callbaks
  • Methods for Playbook Callbaks

Edit: In this case the solution was to extend the AggregateStat class instead. Code examples below provided by @Tom_Sawyyer

from ansible.callbacks import AggregateStats                                 

class CustomAggregateStats(AggregateStats):                                         
"""                                                                             
Holds stats about per-host activity during playbook runs.                       
"""                                                                             
def __init__(self):                                                             
    super(CustomAggregateStats, self).__init__()                                
    self.results = {}                                                           

def compute(self, runner_results, setup=False, poll=False,                      
            ignore_errors=False):                                               
    """                                                                         
    Walk through all results and increment stats.                               
    """                                                                         
    super(CustomAggregateStats, self).compute(runner_results, setup, poll,   
                                              ignore_errors)                    

    for (host, value) in runner_results.get('contacted', {}).iteritems():       
        if 'invocation' in value:                                               
            if value['invocation']['module_name'] == 'service':            
                self.results['service_name'] = value['name']                        

def summarize(self, host):                                                      
    """                                                                         
    Return information about a particular host                                  
    """                                                                         
    summarized_info = super(CustomAggregateStats, self).summarize(host)         

    # Adding the info I need                                                    
    summarized_info['result'] = self.results                                    

    return summarized_info

And finally:

my_stats = CustomAggregateStats()
pb = ansible.playbook.PlayBook(
    ... # basic info
    stats=my_stats,
)     

Giving output:

{"127.0.0.1": {"skipped": 0, "ok": 3, "changed": 2, "result": {"service_name": "apache2"}, "failures": 0, "unreachable": 0}}
like image 96
Lycha Avatar answered Oct 07 '22 18:10

Lycha