最近想利用python来调用anbile来实现一些功能,发现ansible的api已经升级到了2.0,使用上比以前复杂了许多。
这里我参考了官方文档的例子,做了一些整改,写了一个python调用ansible的函数,执行过程中输出执行结果。函数返回执行结果,便于筛选和存储所需的数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
# 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文件如下:
1
2
3
4
|
# more /etc/ansible/hosts
[testserver]
192.168.52.128
192.168.52.135
|
调用如下:
先调用testserver一组主机批量执行date命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
>>> 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"
]
}
}
|
指定单台执行命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
>>> 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 "
}
}
|
这里可以从输出中取到输出结果:
1
2
3
4
5
|
>>> 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 = {}这个空字典,即可实现。
使用如下:
1
2
3
4
|
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'
:
' t
|
本文转自 icenycmh 51CTO博客,原文链接:http://blog.51cto.com/icenycmh/1870642,如需转载请自行联系原作者