ansible
ansible是自动化运维工具,越来越多的底层自动化采用ansible的接口来实现,这个工具也提供可以提供了调用的api接口,ansible官网提供原始的api接口调用实例。
1 | #!/usr/bin/env python |
2 | |
3 | import json |
4 | from collections import namedtuple |
5 | from ansible.parsing.dataloader import DataLoader |
6 | from ansible.vars import VariableManager |
7 | from ansible.inventory import Inventory |
8 | from ansible.playbook.play import Play |
9 | from ansible.executor.task_queue_manager import TaskQueueManager |
10 | from ansible.plugins.callback import CallbackBase |
11 | |
12 | class ResultCallback(CallbackBase): |
13 | """A sample callback plugin used for performing an action as results come in |
14 |
|
15 | If you want to collect all results into a single object for processing at |
16 | the end of the execution, look into utilizing the ``json`` callback plugin |
17 | or writing your own custom callback plugin |
18 | """ |
19 | def v2_runner_on_ok(self, result, **kwargs): |
20 | """Print a json representation of the result |
21 |
|
22 | This method could store the result in an instance attribute for retrieval later |
23 | """ |
24 | host = result._host |
25 | print json.dumps({host.name: result._result}, indent=4) |
26 | |
27 | Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check']) |
28 | # initialize needed objects |
29 | variable_manager = VariableManager() |
30 | loader = DataLoader() |
31 | options = Options(connection='local', module_path='/path/to/mymodules', forks=100, become=None, become_method=None, become_user=None, check=False) |
32 | passwords = dict(vault_pass='secret') |
33 | |
34 | # Instantiate our ResultCallback for handling results as they come in |
35 | results_callback = ResultCallback() |
36 | |
37 | # create inventory and pass to var manager |
38 | inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list='localhost') |
39 | variable_manager.set_inventory(inventory) |
40 | |
41 | # create play with tasks |
42 | play_source = dict( |
43 | name = "Ansible Play", |
44 | hosts = 'localhost', |
45 | gather_facts = 'no', |
46 | tasks = [ |
47 | dict(action=dict(module='shell', args='ls'), register='shell_out'), |
48 | dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) |
49 | ] |
50 | ) |
51 | play = Play().load(play_source, variable_manager=variable_manager, loader=loader) |
52 | |
53 | # actually run it |
54 | tqm = None |
55 | try: |
56 | tqm = TaskQueueManager( |
57 | inventory=inventory, |
58 | variable_manager=variable_manager, |
59 | loader=loader, |
60 | options=options, |
61 | passwords=passwords, |
62 | stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin |
63 | ) |
64 | result = tqm.run(play) |
65 | finally: |
66 | if tqm is not None: |
67 | tqm.cleanup() |
解析下这个api接口示例:
导入必要的模块
1
import json
2
from collections import namedtuple
3
from ansible.parsing.dataloader import DataLoader
4
from ansible.vars import VariableManager
5
from ansible.inventory import Inventory
6
from ansible.playbook.play import Play
7
from ansible.executor.task_queue_manager import TaskQueueManager
8
from ansible.plugins.callback import CallbackBase
定义要使用的命名空间
改部分是api接口的初始化,传入必要的参数。1
Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check'])
2
# initialize needed objects
3
variable_manager = VariableManager()
4
loader = DataLoader()
5
options = Options(connection='local', module_path='/path/to/mymodules', forks=100, become=None, become_method=None, become_user=None, check=False)
6
passwords = dict(vault_pass='secret')
7
8
# Instantiate our ResultCallback for handling results as they come in
9
results_callback = ResultCallback()
10
11
# create inventory and pass to var manager
12
inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list='localhost')
13
variable_manager.set_inventory(inventory)
编写执行的命令
1
play_source = dict(
2
name = "Ansible Play",
3
hosts = 'localhost',
4
gather_facts = 'no',
5
tasks = [
6
dict(action=dict(module='shell', args='ls'), register='shell_out'),
7
dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
8
]
9
)
10
play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
把上面的命令放入执行队列中执行
1
tqm = None
2
try:
3
tqm = TaskQueueManager(
4
inventory=inventory,
5
variable_manager=variable_manager,
6
loader=loader,
7
options=options,
8
passwords=passwords,
9
stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin
10
)
11
result = tqm.run(play)
12
finally:
13
if tqm is not None:
14
tqm.cleanup()
自己修改的api接口
1 | #!/usr/bin/env python |
2 | # -*- coding: UTF-8 -*- |
3 | import json |
4 | from collections import namedtuple |
5 | from ansible.parsing.dataloader import DataLoader |
6 | from ansible.vars import VariableManager |
7 | from ansible.inventory import Inventory |
8 | from ansible.playbook.play import Play |
9 | from ansible.executor.task_queue_manager import TaskQueueManager |
10 | from ansible.plugins.callback import CallbackBase |
11 | |
12 | class ResultCallback(CallbackBase): |
13 | host = result._host |
14 | print (json.dumps({host.name: result._result}, indent=4)) |
15 | |
16 | |
17 | def ansibleRun(host_list,task_list): |
18 | Options = namedtuple('Options', |
19 | ['connection','module_path','forks','remote_user','private_key_file', |
20 | 'ssh_common_args','ssh_extra_args','sftp_extra_args','scp_extra_args', |
21 | 'become','become_method','become_user','verbosity','check']) |
22 | |
23 | |
24 | variable_manager = VariableManager() |
25 | loader = DataLoader() |
26 | options = Options( connection='smart',module_path=None, |
27 | forks=100,remote_user=None,private_key_file=None,ssh_common_args=None,ssh_extra_args=None, |
28 | sftp_extra_args=None,scp_extra_args=None,become=None,become_method=None, |
29 | become_user=None,verbosity=None,check=False |
30 | ) |
31 | |
32 | passwords = dict() |
33 | results_callback = ResultCallback() |
34 | inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=host_list) |
35 | variable_manager.set_inventory(inventory) |
36 | |
37 | play_source = dict( |
38 | name = "Ansible Play", |
39 | hosts = host_list, |
40 | gather_facts = 'no', |
41 | tasks = task_list |
42 | ) |
43 | play = Play().load(play_source, variable_manager=variable_manager, loader=loader) |
44 | |
45 | tqm = None |
46 | try: |
47 | tqm = TaskQueueManager( |
48 | inventory=inventory,variable_manager=variable_manager, |
49 | loader=loader,options=options,passwords=passwords, |
50 | stdout_callback=results_callback, |
51 | ) |
52 | result = tqm.run(play) |
53 | finally: |
54 | if tqm is not None: |
55 | tqm.cleanup() |
56 | |
57 | if __name__ == '__main__': |
58 | host_list = ['10.14.86.177', '10.14.86.178'] |
59 | tasks_list = [ |
60 | dict(action=dict(module='command', args='pwd')), |
61 | dict(action=dict(module='shell', args='python sleep.py')), |
62 | dict(action=dict(module='synchronize', args='src=/home/op/test dest=/home/opt/ delete=yes')), |
63 | ] |
64 | ansibleRun(host_list,tasks_list) |
这样的调用只适合临时命令调用,如果我们需要执行大量自动化任务,需要修改的大量代码,所以我们需要可以封装称调用playbook的方式来使用。
1 | #!/usr/bin/env python |
2 | # -*- coding: UTF-8 -*- |
3 | |
4 | import os |
5 | import sys |
6 | from collections import namedtuple |
7 | form ansible.parsing.dataloader import DataLoader |
8 | from ansible.vars import VariableManager |
9 | from ansible.inventory import Inventory |
10 | from ansible.executor.playbook_executor import PlaybookExecutor |
11 | from ansible.utils.display import log_file |
12 | |
13 | variable_manager = VariableManager() |
14 | loader = DataLoader() |
15 | |
16 | inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list='/etc/ansible/hosts') |
17 | |
18 | Options = namedtuple('Options', |
19 | ['listtags','listtasks','listhosts','synatx','connections','module_path','forks','private_key_file','ssh_common_args', |
20 | 'ssh_extra_args','sftp_extra_args','scp_extra_args','become','become_method','become_user','verbosity','check']) |
21 | |
22 | opotions=Opotions(listtags=False,listtasks=False,listhosts=False,synatx=False,connections='smart',module_path=None,forks=100,private_key_file=None,ssh_common_args=None, |
23 | ssh_extra_args=None,sftp_extra_args=None,scp_extra_args=None,become=False,become_method=None,become_user=None,verbosity=None,check=False) |
24 | |
25 | playbook_path='ping.yml' |
26 | vaiable_manager.extra_vars={'aa':'xx'} |
27 | if not os.path.exists(playbook_path): |
28 | print('[WARING]:The playbook does not exitst') |
29 | sys.exit() |
30 | |
31 | passwords={} |
32 | |
33 | pbex=PlaybookExecutor(playbook=[playbook_path],inventory=inventory,variable_manager=variable_manager,loader=loader,opotions=opotions,passwords=passwords) |
34 | code=pbex.run() |
35 | stats=pbex._tqm_.stats |
36 | hosts=sorted(stats.processed.keys()) |
37 | result=[{h:stats.summarize(h)} for h in hosts] |
38 | results={'code':code,'result':result,'playbook':playbook_path} |
39 | print(results) |
这样的api接口虽然可以返回执行结果,但是无法返回ansible的执行日志,无法快速定位playbook的bug所在,也是无法得到最终用户的认可的,如果我们需要,我们就需要修改其源码了,后续我还需要测试。