|
|
|
@ -26,20 +26,15 @@ as it has a very nice REST API that provides all of these things at a higher lev
|
|
|
|
|
Ansible is written in its own API so you have a considerable amount of power across the board.
|
|
|
|
|
This chapter discusses the Python API.
|
|
|
|
|
|
|
|
|
|
.. _python_api:
|
|
|
|
|
|
|
|
|
|
The Python API is very powerful, and is how the all the ansible CLI tools are implemented.
|
|
|
|
|
In version 2.0 the core ansible got rewritten and the API was mostly rewritten.
|
|
|
|
|
|
|
|
|
|
.. note:: Ansible relies on forking processes, as such the API is not thread safe.
|
|
|
|
|
|
|
|
|
|
.. _python_api_20:
|
|
|
|
|
.. _python_api_example:
|
|
|
|
|
|
|
|
|
|
Python API 2.0
|
|
|
|
|
--------------
|
|
|
|
|
|
|
|
|
|
In 2.0 things get a bit more complicated to start, but you end up with much more discrete and readable classes::
|
|
|
|
|
Python API example
|
|
|
|
|
------------------
|
|
|
|
|
|
|
|
|
|
This example is by no means comphrehensive and is not meant to show you how to use all of Ansible's feautres,
|
|
|
|
|
it is just a simple demonstration on how to minmally run a couple of tasks.::
|
|
|
|
|
|
|
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
|
@ -69,22 +64,24 @@ In 2.0 things get a bit more complicated to start, but you end up with much more
|
|
|
|
|
host = result._host
|
|
|
|
|
print(json.dumps({host.name: result._result}, indent=4))
|
|
|
|
|
|
|
|
|
|
# since API is constructed for CLI it expects certain options to always be set, named tuple 'fakes' the args parsing options object
|
|
|
|
|
Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'diff'])
|
|
|
|
|
options = Options(connection='local', module_path=['/to/mymodules'], forks=10, become=None, become_method=None, become_user=None, check=False, diff=False)
|
|
|
|
|
|
|
|
|
|
# initialize needed objects
|
|
|
|
|
loader = DataLoader()
|
|
|
|
|
options = Options(connection='local', module_path=['/path/to/mymodules'], forks=100, become=None, become_method=None, become_user=None, check=False,
|
|
|
|
|
diff=False)
|
|
|
|
|
loader = DataLoader() # Takes care of finding and reading yaml, json and ini files
|
|
|
|
|
passwords = dict(vault_pass='secret')
|
|
|
|
|
|
|
|
|
|
# Instantiate our ResultCallback for handling results as they come in
|
|
|
|
|
# Instantiate our ResultCallback for handling results as they come in, Ansible expects this to be one of it's main display outlets
|
|
|
|
|
results_callback = ResultCallback()
|
|
|
|
|
|
|
|
|
|
# create inventory and pass to var manager
|
|
|
|
|
# use path to host config file as source or hosts in a comma separated string
|
|
|
|
|
# create inventory, use path to host config file as source or hosts in a comma separated string
|
|
|
|
|
inventory = InventoryManager(loader=loader, sources='localhost,')
|
|
|
|
|
|
|
|
|
|
# variable manager takes care of merging all the different sources to give you a unifed view of variables available in each context
|
|
|
|
|
variable_manager = VariableManager(loader=loader, inventory=inventory)
|
|
|
|
|
|
|
|
|
|
# create play with tasks
|
|
|
|
|
# create datastructure that represents our play, including tasks, this is basically what our YAML loader does internally.
|
|
|
|
|
play_source = dict(
|
|
|
|
|
name = "Ansible Play",
|
|
|
|
|
hosts = 'localhost',
|
|
|
|
@ -94,9 +91,12 @@ In 2.0 things get a bit more complicated to start, but you end up with much more
|
|
|
|
|
dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Create play object, playbook objects use .load instead of init or new methods,
|
|
|
|
|
# this will also automatically create the task objects from the info provided in play_source
|
|
|
|
|
play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
|
|
|
|
|
|
|
|
|
|
# actually run it
|
|
|
|
|
# actually run it, instantiate task queue manager, which takes care of forking and setting up all objects to iterate over host list and tasks
|
|
|
|
|
tqm = None
|
|
|
|
|
try:
|
|
|
|
|
tqm = TaskQueueManager(
|
|
|
|
@ -105,10 +105,11 @@ In 2.0 things get a bit more complicated to start, but you end up with much more
|
|
|
|
|
loader=loader,
|
|
|
|
|
options=options,
|
|
|
|
|
passwords=passwords,
|
|
|
|
|
stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin
|
|
|
|
|
stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin, which prints to stdout
|
|
|
|
|
)
|
|
|
|
|
result = tqm.run(play)
|
|
|
|
|
result = tqm.run(play) # most interesting data for a play is actually sent to the callback's methods
|
|
|
|
|
finally:
|
|
|
|
|
# we always need to cleanup child procs, and the strucutres we use to communicate with them
|
|
|
|
|
if tqm is not None:
|
|
|
|
|
tqm.cleanup()
|
|
|
|
|
|
|
|
|
@ -116,74 +117,7 @@ In 2.0 things get a bit more complicated to start, but you end up with much more
|
|
|
|
|
shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. _python_api_old:
|
|
|
|
|
|
|
|
|
|
Python API pre 2.0
|
|
|
|
|
------------------
|
|
|
|
|
|
|
|
|
|
It's pretty simple::
|
|
|
|
|
|
|
|
|
|
import ansible.runner
|
|
|
|
|
|
|
|
|
|
runner = ansible.runner.Runner(
|
|
|
|
|
module_name='ping',
|
|
|
|
|
module_args='',
|
|
|
|
|
pattern='web*',
|
|
|
|
|
forks=10
|
|
|
|
|
)
|
|
|
|
|
datastructure = runner.run()
|
|
|
|
|
|
|
|
|
|
The run method returns results per host, grouped by whether they
|
|
|
|
|
could be contacted or not. Return types are module specific, as
|
|
|
|
|
expressed in the :doc:`../modules` documentation.::
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
"dark" : {
|
|
|
|
|
"web1.example.com" : "failure message"
|
|
|
|
|
},
|
|
|
|
|
"contacted" : {
|
|
|
|
|
"web2.example.com" : 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
A module can return any type of JSON data it wants, so Ansible can
|
|
|
|
|
be used as a framework to rapidly build powerful applications and scripts.
|
|
|
|
|
|
|
|
|
|
.. _detailed_api_old_example:
|
|
|
|
|
|
|
|
|
|
Detailed API Example
|
|
|
|
|
````````````````````
|
|
|
|
|
|
|
|
|
|
The following script prints out the uptime information for all hosts::
|
|
|
|
|
|
|
|
|
|
#!/usr/bin/python
|
|
|
|
|
|
|
|
|
|
import ansible.runner
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
# construct the ansible runner and execute on all hosts
|
|
|
|
|
results = ansible.runner.Runner(
|
|
|
|
|
pattern='*', forks=10,
|
|
|
|
|
module_name='command', module_args='/usr/bin/uptime',
|
|
|
|
|
).run()
|
|
|
|
|
|
|
|
|
|
if results is None:
|
|
|
|
|
print "No hosts found"
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
print "UP ***********"
|
|
|
|
|
for (hostname, result) in results['contacted'].items():
|
|
|
|
|
if not 'failed' in result:
|
|
|
|
|
print "%s >>> %s" % (hostname, result['stdout'])
|
|
|
|
|
|
|
|
|
|
print "FAILED *******"
|
|
|
|
|
for (hostname, result) in results['contacted'].items():
|
|
|
|
|
if 'failed' in result:
|
|
|
|
|
print "%s >>> %s" % (hostname, result['msg'])
|
|
|
|
|
|
|
|
|
|
print "DOWN *********"
|
|
|
|
|
for (hostname, result) in results['dark'].items():
|
|
|
|
|
print "%s >>> %s" % (hostname, result)
|
|
|
|
|
.. note:: Ansible emits warnings and errors via the display object, which prints directly to stdout, stderr and the Ansible log.
|
|
|
|
|
|
|
|
|
|
Advanced programmers may also wish to read the source to ansible itself,
|
|
|
|
|
for it uses the API (with all available options) to implement the ``ansible``
|
|
|
|
|