ansible API 示例

ansible api 与ansible-playbook api 本应该是后面放在 ansible条件与循环、ansible变量篇之后讲的,不过使用过后实在按捺不住提前写的冲动,这个插个队先讲讲API 部分。

一、ansible api

ansible api 的使用非常强大,也非常简单,只不过把模块需要使用的参数写到了脚本中,这里先来看下官方给的示例,不过同于官方的是,我这里增我将结果进行了json美化输出。

 
 
  1. [root@361way api]# cat test_api.py
  2. #!/usr/bin/env python
  3. # coding=utf-8
  4. import ansible.runner
  5. import json
  6. runner = ansible.runner.Runner(
  7. module_name='ping',
  8. module_args='',
  9. pattern='all',
  10. forks=10
  11. )
  12. datastructure = runner.run()
  13. data = json.dumps(datastructure,indent=4)
  14. print data

其输出结果如下:

ansible-api

注:如果主机是不通或失败的,结果将会输出到dark部分里,一个含有失败主机的结果类似如下:

 
 
  1. {
  2. "dark" : {
  3. "web1.example.com" : "failure message"
  4. },
  5. "contacted" : {
  6. "web2.example.com" : 1
  7. }
  8. }

再为看下第二个示例:

 
 
  1. #!/usr/bin/python
  2. import ansible.runner
  3. import sys
  4. # construct the ansible runner and execute on all hosts
  5. results = ansible.runner.Runner(
  6. pattern='*', forks=10,
  7. module_name='command', module_args='/usr/bin/uptime',
  8. ).run()
  9. if results is None:
  10. print "No hosts found"
  11. sys.exit(1)
  12. print "UP ***********"
  13. for (hostname, result) in results['contacted'].items():
  14. if not 'failed' in result:
  15. print "%s >>> %s" % (hostname, result['stdout'])
  16. print "FAILED *******"
  17. for (hostname, result) in results['contacted'].items():
  18. if 'failed' in result:
  19. print "%s >>> %s" % (hostname, result['msg'])
  20. print "DOWN *********"
  21. for (hostname, result) in results['dark'].items():
  22. print "%s >>> %s" % (hostname, result)

上面的示例中对主机的输出结果进行了判断,并且结果的输出进行了定制化,上面执行的结果你可以和ansible all -m command -a 'uptime' 的结果进行下比对,看下有什么不同。

上面的示例基本上都是参照官方页面进行执行的,更多用法可以通过pydoc ansible或者通过python里的help(ansible)查看。另外在多主机执行时,可以使用async(异部)方式运行。

二、ansible_playbook api

ansible_playbook api 部分在官方文档上并没有提,不过通过查看ansible模块的帮助信息可以看到其是支持的。在ansible google论坛里(需翻墙),有老外也给出里代码,其实它和执行ansible的api方式一样,只是多了个几个参数:

 
 
  1. import ansible.playbook
  2. from ansible import callbacks
  3. from ansible import utils
  4. stats = callbacks.AggregateStats()
  5. playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
  6. runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)
  7. pb = ansible.playbook.PlayBook(
  8. playbook="nseries.yml",
  9. stats=stats,
  10. callbacks=playbook_cb,
  11. runner_callbacks=runner_cb,
  12. check=True
  13. )
  14. for (play_ds, play_basedir) in zip(pb.playbook, pb.play_basedirs):
  15. import ipdb
  16. ipdb.set_trace()
  17. # Can play around here to see what's going on.
  18. pb.run()

大致看了下代码,在用api的方式执行playbook的时候,playbook,stats,callbacks,runner_callbacks这几个参数是必须的。不使用的时候会报错。

 
 
  1. arguments = []
  2. if playbook is None:
  3. arguments.append('playbook')
  4. if callbacks is None:
  5. arguments.append('callbacks')
  6. if runner_callbacks is None:
  7. arguments.append('runner_callbacks')
  8. if stats is None:
  9. arguments.append('stats')
  10. if arguments:
  11. raise Exception('PlayBook missing required arguments: %s' % ', '.join(arguments))

playbook用来指定playbook的yaml文件

stats用来收集playbook执行期间的状态信息,最后会进行汇总

callbacks用来输出playbook执行的结果

runner_callbacks用来输出playbook执行期间的结果。但是它返回的结果太简单,我想让它详细点,如果用自定义callback的方法插入到mongo里面的话也行,或者是直接输出,但是我想所有task都执行完后,把每个task的详细信息输出到终端上,最后发现结果输出都是靠callbacks.py里的AggregateStats这个类,在每执行完一个task后,都会调用AggregateStats进行计算,汇总。

 
 
  1. [root@361way api]# cat playbook_api.py
  2. #!/usr/bin/env python
  3. # coding=utf-8
  4. import ansible.playbook
  5. from ansible import callbacks
  6. from ansible import utils
  7. import json
  8. stats = callbacks.AggregateStats()
  9. playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
  10. runner_cb = callbacks.PlaybookRunnerCallbacks(stats,verbose=utils.VERBOSITY)
  11. res=ansible.playbook.PlayBook(
  12. playbook='/etc/ansible/playbooks/user.yml',
  13. stats=stats,
  14. callbacks=playbook_cb,
  15. runner_callbacks=runner_cb
  16. ).run()
  17. data = json.dumps(res,indent=4)
  18. print data
  19. # 执行结果如下:
  20. [root@361way api]# python playbook_api.py
  21. PLAY [create user] ************************************************************
  22. TASK: [create test "{{ user }}"] **********************************************
  23. changed: [10.212.52.16]
  24. changed: [10.212.52.14]
  25. {
  26. "10.212.52.16": {
  27. "unreachable": 0,
  28. "skipped": 0,
  29. "ok": 1,
  30. "changed": 1,
  31. "failures": 0
  32. },
  33. "10.212.52.14": {
  34. "unreachable": 0,
  35. "skipped": 0,
  36. "ok": 1,
  37. "changed": 1,
  38. "failures": 0
  39. }
  40. }
  41. [root@361way api]#

三、总结

从上面的例子来看,感觉作用似乎有点鸡肋。多条ansible shell 指令的执行可以写成playbook 来执行,ansbile-playbook 也可以通过include 调用子playbook ,似乎API 部分用处并不大 。咋一听深感有理,不过细究一下,

1、当需要先对前一次作任务执行的结果进行处理,并将相应的结果对应的作为输入再在一次任务传入时,这里使用api 更方便;

2、需要对结果输出进行整形时,也比较api 方便;

3、playbook 之间进行调用或都playbook比较复杂时,想要理清任务之间的关系势必累显麻烦,而通过api,从上一层任务到下一层任务之间的调用关系明子。而且playbook之间可以是平行的关系。方便小的功能模块的复用。

4、方便二次开发及和其他程序之间的耦合调用----目前感觉这条是最实用的。




##################################################################################


How can I run a playbook in python script? What is the equivalent of the following using ansible module in python:

ansible -i hosts dbservers -m setup
ansible-playbook -i hosts -vvvv -k site.yml

I was looking at their documenation in http://docs.ansible.com/developing_api.html but they have very limited examples.

share improve this question
 
 
Does my solution not work for you? Need help? –  tristan  Dec 23 '14 at 15:42
 
@tristan, thanks for the reply, I looked into their documentation as you said in your post, but I could not find any explanation or example on how to call ansible-playbook or how to pass certain arguments such as ansible-playbook -i hosts -u foo -k –  helloworld2013  Dec 23 '14 at 17:41 
 
Ah, I've updated my answer. Please accept if you found it helpful, but in the future, it's easier to answer questions that are specific. –  tristan  Dec 23 '14 at 17:59
 
@tristan, very helpful thanks! –  helloworld2013  Dec 23 '14 at 19:55
 
No problem. If you have any more questions, post them and let me know –  tristan  Dec 23 '14 at 20:11

3 Answers

up vote 26 down vote accepted

This covered in the Ansible documentation under "Python API."

For example, ansible -i hosts dbservers -m setup is implemented via:

import ansible.runner

runner = ansible.runner.Runner(
   module_name='setup',
   module_args='',
   pattern='dbservers',
)
dbservers_get_facts = runner.run()

There are a bunch of non-documented parameters in the __init__ method of Runner (from ansible.runner). There's too many to list inline, but I've included some of the parameters in this post as a guess to what you're specifically looking for.

class Runner(object):
    ''' core API interface to ansible '''

    # see bin/ansible for how this is used...

    def __init__(self,
        host_list=C.DEFAULT_HOST_LIST,      # ex: /etc/ansible/hosts, legacy usage
        module_path=None,                   # ex: /usr/share/ansible
        module_name=C.DEFAULT_MODULE_NAME,  # ex: copy
        module_args=C.DEFAULT_MODULE_ARGS,  # ex: "src=/tmp/a dest=/tmp/b"
        ...
        pattern=C.DEFAULT_PATTERN,          # which hosts?  ex: 'all', 'acme.example.org'
        remote_user=C.DEFAULT_REMOTE_USER,  # ex: 'username'
        remote_pass=C.DEFAULT_REMOTE_PASS,  # ex: 'password123' or None if using key
        remote_port=None,                   # if SSH on different ports
        private_key_file=C.DEFAULT_PRIVATE_KEY_FILE, # if not using keys/passwords
        sudo_pass=C.DEFAULT_SUDO_PASS,      # ex: 'password123' or None
        ...
        sudo=False,                         # whether to run sudo or not
        sudo_user=C.DEFAULT_SUDO_USER,      # ex: 'root'
        module_vars=None,                   # a playbooks internals thing
        play_vars=None,                     #
        play_file_vars=None,                #
        role_vars=None,                     #
        role_params=None,                   #
        default_vars=None,                  #
        extra_vars=None,                    # extra vars specified with he playbook(s)
        is_playbook=False,                  # running from playbook or not?
        inventory=None,                     # reference to Inventory object
        ...
        su=False,                           # Are we running our command via su?
        su_user=None,                       # User to su to when running command, ex: 'root'
        su_pass=C.DEFAULT_SU_PASS,
        vault_pass=None,
        ...
        ):

For instance, the above command that specifies a sudo user and pass would be:

runner = ansible.runner.Runner(
   module_name='setup',
   module_args='',
   pattern='dbservers',
   remote_user='some_user'
   remote_pass='some_pass_or_python_expression_that_returns_a_string'
)

For playbooks, look into playbook.PlayBook, which takes a similar set of initializers:

class PlayBook(object):
    '''
    runs an ansible playbook, given as a datastructure or YAML filename.
    ...
    '''

    # *****************************************************

    def __init__(self,
        playbook         = None,
        host_list        = C.DEFAULT_HOST_LIST,
        module_path      = None,
        .... 

and can be executed with the .run() method. e.g.:

from ansible.playbook import PlayBook
pb = PlayBook(playbook='/path/to/book.yml, --other initializers--)
pb.run()

more robust usage can be found in the ansible-playbook file.

As far as I know, translating playbooks to Python modules is a bit more involved, but the documentation listed above should get you covered and you can reuse the YAML parser built into Ansible to convert playbooks to variables.

share improve this answer
 
 
This doesn't seem to answer how to run a playbook, but instead an individual task. There is anansible.playbook.Playbook class with a run method as well which I think the OP is asking about - I know it's what I'm trying to find :D –  fideloper  Mar 25 '15 at 15:32
 
ansible.playbook.Playbook calls to runner for execution (see is_playbook in ansible.runner), but good point. updating answer now. –  tristan  Mar 25 '15 at 16:05 
 
Thank you very much! Also found a good example in (where else?!) the GitHub repo with their ansible-playbook command --- (edit: whoops, you pointed that out already :D ) –  fideloper  Mar 25 '15 at 20:08 
 
@fideloper happy to help. my typical path in extending Ansible is to just hop around in the source or to just kick off pdb and follow it -- Ansible's code base is pretty straightforward. –  tristan  Mar 25 '15 at 20:20

I have answered the question here Posting this here cause posting links is discouraged in the community. Hope it helps.

" The documentation is surprisingly lacking and you'll have to get started here

That being said, here is a quick script I hacked together that manages to run a playbook.

#!/usr/bin/env python

import os
import sys
from collections import namedtuple

from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager
from ansible.inventory import Inventory
from ansible.executor.playbook_executor import PlaybookExecutor

variable_manager = VariableManager()
loader = DataLoader()

inventory = Inventory(loader=loader, variable_manager=variable_manager,  host_list='/home/slotlocker/hosts2')
playbook_path = '/home/slotlocker/ls.yml'

if not os.path.exists(playbook_path):
    print '[INFO] The playbook does not exist'
    sys.exit()

Options = namedtuple('Options', ['listtags', 'listtasks', 'listhosts', 'syntax', 'connection','module_path', 'forks', 'remote_user', 'private_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', 'verbosity', 'check'])
options = Options(listtags=False, listtasks=False, listhosts=False, syntax=False, connection='ssh', module_path=None, forks=100, remote_user='slotlocker', private_key_file=None, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=True, become_method=None, become_user='root', verbosity=None, check=False)

variable_manager.extra_vars = {'hosts': 'mywebserver'} # This can accomodate various other command line arguments.`

passwords = {}

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

results = pbex.run()



##################################################################################################

http://www.cnblogs.com/xpxstar/p/4940281.html

http://rfyiamcool.blog.51cto.com/1030776/1353618

http://rfyiamcool.blog.51cto.com/1030776/1413031/

https://fedorahosted.org/cobbler/wiki/CobblerApi

https://fedorahosted.org/cobbler/wiki/CobblerXmlrpc


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值