ansible api 与ansible-playbook api 本应该是后面放在 ansible条件与循环、ansible变量篇之后讲的,不过使用过后实在按捺不住提前写的冲动,这个插个队先讲讲API 部分。
一、ansible api
ansible api 的使用非常强大,也非常简单,只不过把模块需要使用的参数写到了脚本中,这里先来看下官方给的示例,不过同于官方的是,我这里增我将结果进行了json美化输出。
- [root@361way api]# cat test_api.py
- #!/usr/bin/env python
- # coding=utf-8
- import ansible.runner
- import json
- runner = ansible.runner.Runner(
- module_name='ping',
- module_args='',
- pattern='all',
- forks=10
- )
- datastructure = runner.run()
- data = json.dumps(datastructure,indent=4)
- print data
其输出结果如下:
注:如果主机是不通或失败的,结果将会输出到dark部分里,一个含有失败主机的结果类似如下:
- {
- "dark" : {
- "web1.example.com" : "failure message"
- },
- "contacted" : {
- "web2.example.com" : 1
- }
- }
再为看下第二个示例:
- #!/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)
上面的示例中对主机的输出结果进行了判断,并且结果的输出进行了定制化,上面执行的结果你可以和ansible all -m command -a 'uptime' 的结果进行下比对,看下有什么不同。
上面的示例基本上都是参照官方页面进行执行的,更多用法可以通过pydoc ansible或者通过python里的help(ansible)查看。另外在多主机执行时,可以使用async(异部)方式运行。
二、ansible_playbook api
ansible_playbook api 部分在官方文档上并没有提,不过通过查看ansible模块的帮助信息可以看到其是支持的。在ansible google论坛里(需翻墙),有老外也给出里代码,其实它和执行ansible的api方式一样,只是多了个几个参数:
- import ansible.playbook
- from ansible import callbacks
- from ansible import utils
- stats = callbacks.AggregateStats()
- playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
- runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)
- pb = ansible.playbook.PlayBook(
- playbook="nseries.yml",
- stats=stats,
- callbacks=playbook_cb,
- runner_callbacks=runner_cb,
- check=True
- )
- for (play_ds, play_basedir) in zip(pb.playbook, pb.play_basedirs):
- import ipdb
- ipdb.set_trace()
- # Can play around here to see what's going on.
- pb.run()
大致看了下代码,在用api的方式执行playbook的时候,playbook,stats,callbacks,runner_callbacks这几个参数是必须的。不使用的时候会报错。
- arguments = []
- if playbook is None:
- arguments.append('playbook')
- if callbacks is None:
- arguments.append('callbacks')
- if runner_callbacks is None:
- arguments.append('runner_callbacks')
- if stats is None:
- arguments.append('stats')
- if arguments:
- 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进行计算,汇总。
- [root@361way api]# cat playbook_api.py
- #!/usr/bin/env python
- # coding=utf-8
- import ansible.playbook
- from ansible import callbacks
- from ansible import utils
- import json
- stats = callbacks.AggregateStats()
- playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
- runner_cb = callbacks.PlaybookRunnerCallbacks(stats,verbose=utils.VERBOSITY)
- res=ansible.playbook.PlayBook(
- playbook='/etc/ansible/playbooks/user.yml',
- stats=stats,
- callbacks=playbook_cb,
- runner_callbacks=runner_cb
- ).run()
- data = json.dumps(res,indent=4)
- print data
- # 执行结果如下:
- [root@361way api]# python playbook_api.py
- PLAY [create user] ************************************************************
- TASK: [create test "{{ user }}"] **********************************************
- changed: [10.212.52.16]
- changed: [10.212.52.14]
- {
- "10.212.52.16": {
- "unreachable": 0,
- "skipped": 0,
- "ok": 1,
- "changed": 1,
- "failures": 0
- },
- "10.212.52.14": {
- "unreachable": 0,
- "skipped": 0,
- "ok": 1,
- "changed": 1,
- "failures": 0
- }
- }
- [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.
|
asked
Dec 21 '14 at 14:00
|
|
|
|
|
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.
|
|
answered
Dec 22 '14 at 7:03
| |
|
|
|
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
|