最近想利用python来调用anbile来实现一些功能,发现ansible的api已经升级到了2.0,使用上比以前复杂了许多。
这里我参考了官方文档的例子,做了一些整改,写了一个python调用ansible的函数,执行过程中输出执行结果。函数返回执行结果,便于筛选和存储所需的数据:
# vim exec_ansible.py from ansible.inventory.manager import InventoryManager from ansible.playbook.play import Play from ansible.executor.task_queue_manager import TaskQueueManager from ansible.plugins.callback import CallbackBase class ResultCallback(CallbackBase): """A sample callback plugin used for performing an action as results come in If you want to collect all results into a single object for processing at the end of the execution, look into utilizing the ``json`` callback plugin or writing your own custom callback plugin """ def v2_runner_on_ok(self, result, **kwargs): """Print a json representation of the result This method could store the result in an instance attribute for retrieval later """ global exec_result host = result._host self.data = json.dumps({host.name: result._result}, indent=4) exec_result = dict(exec_result,**json.loads(self.data)) def exec_ansible(module,args,host): Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'diff']) # initialize needed objects loader = DataLoader() options = Options(connection='ssh', module_path='/usr/local/lib/python3.6/site-packages/ansible-2.4.1.0-py3.6.egg/ansible/modules/', forks=100, become=None, become_method=None, become_user=None, check=False,diff=False) passwords = dict(vault_pass='secret') # Instantiate our ResultCallback for handling results as they come in results_callback = ResultCallback() # create inventory and pass to var manager inventory = InventoryManager(loader=loader, sources=['/etc/ansible/hosts']) variable_manager = VariableManager(loader=loader, inventory=inventory) # create play with tasks play_source = dict( name = "Ansible Play", hosts = host, gather_facts = 'no', tasks = [ dict(action=dict(module=module, args=args), register='shell_out'), ] ) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # actually run it tqm = None global exec_result try: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords, stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() return exec_result
调用例子:
我本地ansible的hosts文件如下:
# more /etc/ansible/hosts [testserver] 192.168.52.128 192.168.52.135
调用如下:
先调用testserver一组主机批量执行date命令:
>>> from exec_ansible import exec_ansible >>> test1 = exec_ansible(module='shell',args='date',host='testserver') { "192.168.52.135": { "warnings": [], "stderr": "", "delta": "0:00:00.003688", "_ansible_no_log": false, "stdout": "Sat Nov 5 18:54:17 CST 2016", "cmd": "date", "_ansible_parsed": true, "rc": 0, "invocation": { "module_args": { "removes": null, "executable": null, "creates": null, "chdir": null, "warn": true, "_raw_params": "date", "_uses_shell": true }, "module_name": "command" }, "start": "2016-11-05 18:54:17.563525", "changed": true, "end": "2016-11-05 18:54:17.567213", "stdout_lines": [ "Sat Nov 5 18:54:17 CST 2016" ] } } { "192.168.52.128": { "warnings": [], "stderr": "", "delta": "0:00:00.003244", "_ansible_no_log": false, "stdout": "Sat Nov 5 21:48:38 CST 2016", "cmd": "date", "_ansible_parsed": true, "rc": 0, "invocation": { "module_args": { "removes": null, "executable": null, "creates": null, "chdir": null, "warn": true, "_raw_params": "date", "_uses_shell": true }, "module_name": "command" }, "start": "2016-11-05 21:48:38.252785", "changed": true, "end": "2016-11-05 21:48:38.256029", "stdout_lines": [ "Sat Nov 5 21:48:38 CST 2016" ] } }
指定单台执行命令:
>>> test2 = exec_ansible(module='shell',args='free -m',host='192.168.52.128') { "192.168.52.128": { "warnings": [], "changed": true, "invocation": { "module_args": { "_raw_params": "free -m", "executable": null, "chdir": null, "creates": null, "removes": null, "_uses_shell": true, "warn": true }, "module_name": "command" }, "rc": 0, "start": "2016-11-05 21:53:10.738545", "_ansible_parsed": true, "delta": "0:00:00.002871", "stdout_lines": [ " total used free shared buffers cached", "Mem: 1869 1786 83 3 312 512", "-/+ buffers/cache: 961 908 ", "Swap: 4047 3 4044 " ], "stderr": "", "end": "2016-11-05 21:53:10.741416", "cmd": "free -m", "_ansible_no_log": false, "stdout": " total used free shared buffers cached\nMem: 1869 1786 83 3 312 512\n-/+ buffers/cache: 961 908 \nSwap: 4047 3 4044 " } }
这里可以从输出中取到输出结果:
>>> stdout = test2["192.168.52.128"]["stdout"] total used free shared buffers cached Mem: 1869 1756 112 2 314 490 -/+ buffers/cache: 951 917 Swap: 4047 4 4043
我写的脚本有个bug,就是当指定一组主机批量执行的时候,返回的函数中,存储内容的只剩下最后执行命令的那台主机的相关信息,做不到把所有的主机的执行信息存储,希望有大神可以解决这个问题,并不吝赐教!!(已解决,参考更改过的exec_ansible脚本)
-------后续更新---------------
注:
新版本的api相关模块已经修改,故使用方法上也需要整改,本文档的例子已更新api的使用,如上的exec_ansible脚本。
-----bug解决----
另外,我在脚本中新增了全局空字典参数exec_result={},分别在class ResultCallback和函数exec_result中进行全局函数声明,用以存储执行过程中所产生的stdout输出,以解决之前脚本的bug(返回函数中,存储内容的只剩下最后执行命令的那台主机的相关信息,做不到把所有的主机的执行信息存储)。
只需在python主体重定义exec_result = {}这个空字典,即可实现。
使用如下:
exec_result = {} a = exec_ansible("shell","free -m","test") print(a) {'192.168.204.128': {'changed': True, 'end': '2017-11-07 15:16:08.970746', 'stdout': ' total used free shared buffers cached\nMem: 1990 1918 72 3 89 1280\n-/+ buffers/cache: 548 1441\nSwap: 1999 0 1999', 'cmd': 'free -m', 'rc': 0, 'start': '2017-11-07 15:16:08.964010', 'stderr': '', 'delta': '0:00:00.006736', 'invocation': {'module_args': {'warn': True, 'executable': None, '_uses_shell': True, '_raw_params': 'free -m', 'removes': None, 'creates': None, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': [' total used free shared buffers cached', 'Mem: 1990 1918 72 3 89 1280', '-/+ buffers/cache: 548 1441', 'Swap: 1999 0 1999'], 'stderr_lines': [], '_ansible_no_log': False, 'failed': False}, '192.168.204.129': {'changed': True, 'end': '2017-11-07 15:16:08.975201', 'stdout': ' total used free shared buffers cached\nMem: 1990 1918 72 3 89 1280\n-/+ buffers/cache: 548 1441\nSwap: 1999 0 1999', 'cmd': 'free -m', 'rc': 0, 'start': '2017-11-07 15:16:08.964947', 'stderr': '', 'delta': '0:00:00.010254', 'invocation': {'module_args': {'warn': True, 'executable': None, '_uses_shell': True, '_raw_params': 'free -m', 'removes': None, 'creates': None, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': [' total used free shared buffers cached', 'Mem: 1990 1918 72 3 89 1280', '-/+ buffers/cache: 548 1441', 'Swap: 1999 0 1999'], 'stderr_lines': [], '_ansible_no_log': False, 'failed': False}}