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接口示例:
导入必要的模块
1import json2from collections import namedtuple3from ansible.parsing.dataloader import DataLoader4from ansible.vars import VariableManager5from ansible.inventory import Inventory6from ansible.playbook.play import Play7from ansible.executor.task_queue_manager import TaskQueueManager8from ansible.plugins.callback import CallbackBase定义要使用的命名空间
改部分是api接口的初始化,传入必要的参数。1Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check'])2# initialize needed objects3variable_manager = VariableManager()4loader = DataLoader()5options = Options(connection='local', module_path='/path/to/mymodules', forks=100, become=None, become_method=None, become_user=None, check=False)6passwords = dict(vault_pass='secret')78# Instantiate our ResultCallback for handling results as they come in9results_callback = ResultCallback()1011# create inventory and pass to var manager12inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list='localhost')13variable_manager.set_inventory(inventory)编写执行的命令
1play_source = dict(2name = "Ansible Play",3hosts = 'localhost',4gather_facts = 'no',5tasks = [6dict(action=dict(module='shell', args='ls'), register='shell_out'),7dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))8]9)10play = Play().load(play_source, variable_manager=variable_manager, loader=loader)把上面的命令放入执行队列中执行
1tqm = None2try:3tqm = TaskQueueManager(4inventory=inventory,5variable_manager=variable_manager,6loader=loader,7options=options,8passwords=passwords,9stdout_callback=results_callback, # Use our custom callback instead of the ``default`` callback plugin10)11result = tqm.run(play)12finally:13if tqm is not None:14tqm.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所在,也是无法得到最终用户的认可的,如果我们需要,我们就需要修改其源码了,后续我还需要测试。