参考: https://cloud.tencent.com/info/81cc49e1a4e0bc50fd9675ec38ba6ded.html
https://segmentfault.com/a/1190000008009639
1. 自定义模块的编写
1.1 更改配置文件,让ansible程序能识别模块
library = /usr/share/my_ansible_modules/ #在该路径下的模块能够被ansible识别
1.2 模块编写,最简化的例子:
#-*- encoding: utf-8
#!/usr/bin/python
from ansible.module_utils.basic import * import os
#对模块传入必要的参数 module = AnsibleModule(argument_spec=dict( args=dict(required=True), )) args = module.params['args']
#执行要执行的shell命令,{0}是占位符. os.system('echo {0}'.format(args))
#提供结果信息 result = dict(echo = args,changed=True)
#退出模块,返回信息. module.exit_json(**result)
2. 2.x API的使用
基于 ansible 2.5来写的
参考: ansible 2.6 官方文档
https://www.cnblogs.com/FRESHMANS/p/8391921.html
ansible 权威指南 ---web自动开发
2.1 非调用playbok的方法来调用API.
参考: https://www.cnblogs.com/FRESHMANS/p/8391921.html
例子一:
#-*- encoding: utf-8 #!/usr/bin/python import json import shutil import os from collections import namedtuple from ansible.parsing.dataloader import DataLoader from ansible.vars.manager import VariableManager from ansible.inventory.manager import InventoryManager from ansible.playbook.play import Play from ansible.executor.task_queue_manager import TaskQueueManager from tempfile import NamedTemporaryFile from ansible.plugins.callback import CallbackBase import ansible.constants as C #自定义回调 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 # """ # # host = result._host # # self.data=json.dumps({host.name: result._result}) # # # return self.data # # print self.data # # # def v2_runner_on_failed(self, result,**kwargs): # # host = result._host # # # self.runner_on_failed(host, result._result, ignore_errors) # # self.data = json.dump({host.name: result._result}, indent=4) # # print self.data # # # def v2_on_any(self, *args, **kwargs): # # print args # # print kwargs def __init__(self, *args): super(ResultCallback, self).__init__(display=None) self.status_ok = json.dumps({}) self.status_fail = json.dumps({}) self.status_unreachable = json.dumps({}) self.host_ok = {} self.host_failed = {} self.host_unreachable = {} def v2_runner_on_ok(self, result): host = result._host.get_name() self.runner_on_ok(host, result._result) self.status_ok=json.dumps({host:result._result},indent=4) self.host_ok[host] = result print self.status_ok def v2_runner_on_failed(self, result, ignore_errors=False): host = result._host.get_name() self.runner_on_failed(host, result._result, ignore_errors) self.status_fail=json.dumps({host:result._result},indent=4) self.host_failed[host] = result print self.status_fail def v2_runner_on_unreachable(self, result): host = result._host.get_name() self.runner_on_unreachable(host, result._result) self.status_unreachable=json.dumps({host:result._result},indent=4) self.host_unreachable[host] = result print self.status_unreachable #设置选项,这里是2.5的选项 Option = namedtuple('Option',['listhosts','syntaxcheck','connection','module_path','forks', 'private_key_file','ssh_common_args','ssh_extra_args','sftp_extra_args', 'scp_extra_args','become','become_method','become_user','verbose', 'check','askbecomepass','asksupass','asksudopass','askpass','askvaultpass','diff']) #实例化,负责寻找和阅读yml,json,int文件 loader = DataLoader() #实例化处理结果 result_callback = ResultCallback() option = Option(listhosts=False,syntaxcheck=True,connection="smart",module_path=None,forks=8, private_key_file=None,ssh_common_args=None,ssh_extra_args=None,sftp_extra_args=None, scp_extra_args=None,become=None,become_method=None,become_user=None,verbose=None, check=False,askbecomepass=None,askpass=None,asksudopass=None,asksupass=None,askvaultpass=None,diff=False) passwords = {} hosts = '172.10.30.228,172.10.30.254' #创建库存,使用主机配置文件的路径作为源或主机在一个逗号分隔的字符串。 inventory = InventoryManager(loader=loader,sources=hosts) #负责合并不同来源的变量,比如yml文件,比如hosts # variable_manager.set_inventory(inventory) variable_manager = VariableManager(loader=loader,inventory=inventory) #创建play的数据结构,就相当于是一个平常用的yml文件(也相当于一个ansible命令)。 play_source= dict( name = "ansible Play", hosts = hosts, gather_facts = 'no', tasks = [ dict(action=dict(module='shell',args='ls'),register='shell_out'), dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ] ) #创建play对象,也将自动创建task对象。 play = Play().load(play_source,variable_manager=variable_manager,loader=loader) tqm=None try: tqm = TaskQueueManager( inventory = inventory, variable_manager = variable_manager, loader = loader, options= option, passwords=passwords, # stdout_callback='default', #默认回调插件 stdout_callback=result_callback,#这里使用自定义的回调. # stderr_callback=result_callback, ) result = tqm.run(play) #play的执行结果发送到了 callback method. # print result_callback.status_unreachable,result_callback.host_unreachable #在这里输出结果比在上面ResultCallback中输出的信息简单些. finally: if tqm is not None: tqm.cleanup() shutil.rmtree(C.DEFAULT_LOCAL_TMP,True)
例子2:
#!/usr/bin/env python #-*-coding:utf-8 -*- import json from collections import namedtuple from ansible.parsing.dataloader import DataLoader from ansible.vars.manager import VariableManager #这里用的ansbile 2.4 from ansible.inventory.manager import InventoryManager #这里用的ansible 2.4 from ansible.playbook.play import Play from ansible.executor.task_queue_manager import TaskQueueManager from ansible.plugins.callback import CallbackBase #自定义运行callback,即运行完api后调用v2_runner_on_ok函数,打印host和result class ResultCallback(CallbackBase): def v2_runner_on_ok(self, result, **kwargs): #result所包含属性(_check_key..可用dir方法查看所包含的所有属性) host = result._host print(json.dumps({host.name: result._result}, indent=4)) #创建一个Options类型,列表里为属性,这里用来设置ansible执行时的参数,如ask_pass,sudo_user等等(namedtuple创建一个和tuple类似的对象,而且对象拥有可以访问的属性) Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'diff']) # initialize needed objects loader = DataLoader() #可以通过options.(属性) 的方法去获取属性的值,如获取connection的值可以直接写成options.connection options = Options(connection='local', module_path='/path/to/mymodules', 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() # 加载inventory变量,这里的sources的值可以是hosts文件,也可以是ip列表,如['xxx.xxx.xx.x','xx.xx.xx.xx'] inventory = InventoryManager(loader=loader, sources=['/etc/ansible/hosts']) #管理变量的类,包括主机、组、扩展等变量 variable_manager = VariableManager(loader=loader, inventory=inventory) # 创建一个任务 play_source = dict( name = "Ansible Play", hosts = 'test', #这里写在上面inventory里设置的sources所指定的文件里的组名 gather_facts = 'no', tasks = [ dict(action=dict(module='shell', args='ls'), register='shell_out'), dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ] ) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) # actually run it tqm = None try: tqm = TaskQueueManager( #详细参数看源码 inventory=inventory, variable_manager=variable_manager, loader=loader, #ansible.parsing.dataloader模块创建,用于数据解析 options=options, #存放各类配置信息,ansible执行时的各种参数 passwords=passwords, #登录密码 stdout_callback=results_callback, #回调函数,调用最上面定义的callback函数 ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup()
2.2 调用playbook的方法来调用API
实验成功的一个例子:
#!/usr/bin/python # --*-- coding:utf-8 --*-- import json import logging from ansible.parsing.dataloader import DataLoader from ansible.vars.manager import VariableManager from ansible.inventory.manager import InventoryManager from ansible.playbook.play import Play from ansible.executor.task_queue_manager import TaskQueueManager from ansible.executor.playbook_executor import PlaybookExecutor from ansible.plugins.callback import CallbackBase from collections import namedtuple from ansible import constants as C import ansible.executor.task_result import multiprocessing class ResultsCollector(CallbackBase): def v2_runner_on_ok(self, result): host = result._host logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='/root/cmdb/script/publish.log', filemode='w' ) logging.warning('===v2_runner_on_ok===host=%s===result=%s' % (host, result._result)) # print(json.dumps({host.name: result._result}, indent=4)) def v2_runner_on_failed(self, result, ignore_errors=False): host = result._host logging.warning('===v2_runner_on_failed====host=%s===result=%s' % (host, result._result)) def v2_runner_on_unreachable(self, result): host = result._host logging.warning('===v2_runner_on_unreachable====host=%s===result=%s' % (host, result._result)) class AnsibleAPI(object): def __init__(self, hostlist, image_name, playbooks, *args, **kwargs): self.playbooks = playbooks self.passwords = None self.callback = None Options = namedtuple('Options', ['connection', 'remote_user', 'ask_sudo_pass', 'verbosity', 'ack_pass', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'listhosts', 'listtasks', 'listtags', 'syntax', 'sudo_user', 'sudo', 'diff']) self.options = Options(connection='smart', remote_user='root', ack_pass=None, sudo_user='root', forks=5, sudo='yes', ask_sudo_pass=False, verbosity=5, module_path=None, become=True, become_method='sudo', become_user='root', check=None, listhosts=False, listtasks=False, listtags=None, syntax=None, diff=False) self.loader = DataLoader() self.inventory = InventoryManager(loader=self.loader, sources=hostlist) #source 可以是hosts文件,一可以是用逗号分隔的host组成的字符串。 self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) #实例化变量管理,yml中的变量,inventory中的变量。 self.variable_manager.extra_vars = {"image_name": image_name, 'host': hostlist} #额外的变量,可以在playbook中引用. def runplaybook(self): playbook = PlaybookExecutor( playbooks=self.playbooks, inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, options=self.options, passwords=None) playbook._tqm._stdout_callback = ResultsCollector() playbook.run() if __name__ == '__main__': # 创建对象 an1 = AnsibleAPI('172.10.30.228,172.10.30.254', '/root/temp/cross.rar', ['/root/temp/main.yml']) # an2 = AnsibleAPI('192.168.194.128','common-oss-dc3a25.tar',['/etc/ansible/update.yml']) # processes = [] p1 = multiprocessing.Process(name='process_one', target=an1.runplaybook) # p2 = multiprocessing.Process(name='process_two',target=an1.runplaybook) # processes.append(p1) # processes.append(p2) # for p in processes: # p.start() # 等待子进程结束,主进程退出 # for p in processes: # p.join() #可以加浮点数参数,等待多久就不等了 p1.start() if p1.is_alive(): print('正在发布') else: print('发布结束')
注意: 运行结果可以这样来取:
print (result._host,result._result.get('cmd'),result._result.get('stdout'),result._result.get("msg"))
main.yml 如下:
[root@chehce temp]# cat main.yml --- - hosts: "{{host}}" #上面建脚本中定义的:self.variable_manager.extra_vars
gather_facts: no #关掉信息收集,节约时间,还有避免 tasks: - name: test copy copy: src="{{image_name}}" dest=/mnt/ backup=yes #这里的变量是在 上面的
结果如下:
正在发布 Wednesday 11 July 2018 11:41:11 +0800 (0:00:00.077) 0:00:00.077 ******** WARNING:root:===v2_runner_on_unreachable====host=172.10.30.254===result={'msg': u'Failed to connect to the host via ssh: OpenSSH_6.6.1, OpenSSL 1.0.1e-fips 11 Feb 2013\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug1: /etc/ssh/ssh_config line 56: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug1: Control socket "/root/.ansible/cp/31fc9148ec" does not exist\r\ndebug2: ssh_connect: needpriv 0\r\ndebug1: Connecting to 172.10.30.254 [172.10.30.254] port 22.\r\ndebug2: fd 3 setting O_NONBLOCK\r\ndebug1: connect to address 172.10.30.254 port 22: Connection refused\r\nssh: connect to host 172.10.30.254 port 22: Connection refused\r\n', 'unreachable': True, 'changed': False} WARNING:root:===v2_runner_on_ok===host=172.10.30.228===result={'_ansible_parsed': True, '_ansible_no_log': False, 'changed': False, '_ansible_verbose_override': True, u'invocation': {u'module_args': {u'filter': u'*', u'gather_subset': [u'all'], u'fact_path': u'/etc/ansible/facts.d', u'gather_timeout': 10}}, u'ansible_facts': {u'ansible_product_serial': u'NA', u'ansible_form_factor': u'Other', u'ansible_python_version': u'2.7.6', u'ansible_distribution_file_parsed': True, u'ansible_fips': False, u'ansible_service_mgr': u'upstart', u'ansible_user_id': u'root', u'ansible_selinux_python_present': False, u'ansible_memtotal_mb': 2001, u'ansible_all_ipv4_addresses': [u'172.10.30.228'], u'gather_subset': [u'all'], u'ansible_architecture': u'x86_64', u'ansible_local': {}, u'ansible_distribution_version': u'14.04', u'ansible_domain': u'', u'ansible_distribution_file_path': u'/etc/os-release', u'ansible_virtualization_type': u'kvm', u'ansible_real_user_id': 0, u'ansible_processor_cores': 1, u'ansible_virtualization_role': u'guest', u'ansible_distribution_file_variety': u'Debian', u'ansible_dns': {u'nameservers': [u'61.139.2.69', u'8.8.8.8']}, u'ansible_effective_group_id': 0, u'ansible_bios_version': u'0.5.1', u'ansible_processor': [u'0', u'GenuineIntel', u'Intel Core i7 9xx (Nehalem Class Core i7)'], u'ansible_date_time': {u'weekday_number': u'3', u'iso8601_basic_short': u'20180711T114121', u'tz': u'CST', u'weeknumber': u'28', u'hour': u'11', u'time': u'11:41:21', u'tz_offset': u'+0800', u'month': u'07', u'epoch': u'1531280481', u'iso8601_micro': u'2018-07-11T03:41:21.519513Z', u'weekday': u'Wednesday', u'iso8601_basic': u'20180711T114121519415', u'year': u'2018', u'date': u'2018-07-11', u'iso8601': u'2018-07-11T03:41:21Z', u'day': u'11', u'minute': u'41', u'second': u'21'}, u'ansible_lo': {u'features': {u'tx_checksum_ipv4': u'off [fixed]', u'generic_receive_offload': u'on', u'tx_checksum_ipv6': u'off [fixed]', u'tx_scatter_gather_fraglist': u'on [fixed]', u'rx_all': u'off [fixed]', u'highdma': u'on [fixed]', u'rx_fcs': u'off [fixed]', u'tx_lockless': u'on [fixed]', u'tx_tcp_ecn_segmentation': u'on', u'tx_gso_robust': u'off [fixed]', u'tx_ipip_segmentation': u'off [fixed]', u'tx_checksumming': u'on', u'vlan_challenged': u'on [fixed]', u'loopback': u'on [fixed]', u'fcoe_mtu': u'off [fixed]', u'tx_checksum_sctp': u'on [fixed]', u'tx_vlan_stag_hw_insert': u'off [fixed]', u'rx_vlan_stag_hw_parse': u'off [fixed]', u'tx_nocache_copy': u'off [fixed]', u'rx_vlan_stag_filter': u'off [fixed]', u'large_receive_offload': u'off [fixed]', u'tx_checksum_ip_generic': u'on [fixed]', u'rx_checksumming': u'on [fixed]', u'tx_tcp_segmentation': u'on', u'tx_fcoe_segmentation': u'off [fixed]', u'busy_poll': u'off [fixed]', u'generic_segmentation_offload': u'on', u'tx_udp_tnl_segmentation': u'off [fixed]', u'tcp_segmentation_offload': u'on', u'l2_fwd_offload': u'off [fixed]', u'rx_vlan_offload': u'off [fixed]', u'ntuple_filters': u'off [fixed]', u'rx_vlan_filter': u'off [fixed]', u'tx_tcp6_segmentation': u'on', u'udp_fragmentation_offload': u'on', u'scatter_gather': u'on', u'tx_sit_segmentation': u'off [fixed]', u'tx_checksum_fcoe_crc': u'off [fixed]', u'tx_scatter_gather': u'on [fixed]', u'netns_local': u'on [fixed]', u'tx_vlan_offload': u'off [fixed]', u'receive_hashing': u'off [fixed]', u'tx_gre_segmentation': u'off [fixed]'}, u'hw_timestamp_filters': [], u'mtu': 65536, u'active': True, u'promisc': False, u'timestamping': [u'rx_software', u'software'], u'ipv4': {u'broadcast': u'host', u'netmask': u'255.0.0.0', u'network': u'127.0.0.0', u'address': u'127.0.0.1'}, u'ipv6': [{u'scope': u'host', u'prefix': u'128', u'address': u'::1'}], u'device': u'lo', u'type': u'loopback'}, u'ansible_userspace_bits': u'64', u'ansible_ssh_host_key_ecdsa_public': u'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOZlxIQEz2PwVxbHC+zqbAllC/oPpPC7nHTXyXu/e4ADmPWg9OxFQsxZQss8KZSGxAKGbnnsyveQVFvxWTlKIl4=', u'ansible_device_links': {u'masters': {}, u'labels': {}, u'ids': {}, u'uuids': {u'vda5': [u'fe8ce998-2fb1-4917-9a88-a0b6bd543dd6'], u'vda1': [u'0c92f976-1be3-45b0-91b7-9ac287522ca3'], u'vdb1': [u'33bf4881-0ad0-4416-a80e-8523315b7ddc']}}, u'ansible_default_ipv4': {u'macaddress': u'52:54:00:b0:48:20', u'network': u'172.10.30.0', u'mtu': 1500, u'broadcast': u'172.10.30.255', u'alias': u'eth0', u'netmask': u'255.255.255.0', u'address': u'172.10.30.228', u'interface': u'eth0', u'type': u'ether', u'gateway': u'172.10.30.254'}, u'ansible_swapfree_mb': 711, u'ansible_default_ipv6': {}, u'ansible_distribution_release': u'trusty', u'ansible_system_vendor': u'Red Hat', u'ansible_os_family': u'Debian', u'ansible_cmdline': {u'root': u'UUID=0c92f976-1be3-45b0-91b7-9ac287522ca3', u'ro': True, u'BOOT_IMAGE': u'/boot/vmlinuz-4.2.0-27-generic'}, u'ansible_effective_user_id': 0, u'ansible_mounts': [{u'block_used': 1409993, u'uuid': u'N/A', u'size_total': 7262953472, u'block_total': 1773182, u'mount': u'/', u'block_available': 363189, u'size_available': 1487622144, u'fstype': u'ext4', u'inode_total': 458752, u'inode_available': 278424, u'device': u'/dev/vda1', u'inode_used': 180328, u'block_size': 4096, u'options': u'rw,errors=remount-ro'}], u'ansible_selinux': {u'status': u'Missing selinux Python library'}, u'ansible_product_version': u'RHEL 7.0.0 PC (i440FX + PIIX, 1996)', u'ansible_apparmor': {u'status': u'enabled'}, u'ansible_userspace_architecture': u'x86_64', u'ansible_product_uuid': u'8C074745-876B-45FE-994D-F4ECCC0CBA6A', u'ansible_fqdn': u'u1', u'ansible_product_name': u'KVM', u'ansible_pkg_mgr': u'apt', u'ansible_memfree_mb': 23, u'ansible_devices': {u'ram14': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram15': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram12': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram13': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram10': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram11': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram8': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram9': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram4': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram5': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram6': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram7': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram0': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram1': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram2': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'ram3': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'131072', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'4096', u'model': None, u'size': u'64.00 MB', u'holders': [], u'partitions': {}}, u'loop3': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'0', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'0', u'model': None, u'size': u'0.00 Bytes', u'holders': [], u'partitions': {}}, u'loop2': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'0', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'0', u'model': None, u'size': u'0.00 Bytes', u'holders': [], u'partitions': {}}, u'loop1': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'0', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'0', u'model': None, u'size': u'0.00 Bytes', u'holders': [], u'partitions': {}}, u'loop0': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'0', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'0', u'model': None, u'size': u'0.00 Bytes', u'holders': [], u'partitions': {}}, u'loop7': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'0', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'0', u'model': None, u'size': u'0.00 Bytes', u'holders': [], u'partitions': {}}, u'loop6': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'0', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'0', u'model': None, u'size': u'0.00 Bytes', u'holders': [], u'partitions': {}}, u'loop5': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'0', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'0', u'model': None, u'size': u'0.00 Bytes', u'holders': [], u'partitions': {}}, u'loop4': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': None, u'sectors': u'0', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'0', u'model': None, u'size': u'0.00 Bytes', u'holders': [], u'partitions': {}}, u'vda': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': u'0x1af4', u'sectors': u'16777216', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'SCSI storage controller: Red Hat, Inc Virtio block device', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'0', u'model': None, u'size': u'8.00 GB', u'holders': [], u'partitions': {u'vda5': {u'sectorsize': 512, u'uuid': u'fe8ce998-2fb1-4917-9a88-a0b6bd543dd6', u'sectors': u'2093056', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': [u'fe8ce998-2fb1-4917-9a88-a0b6bd543dd6']}, u'start': u'14682112', u'holders': [], u'size': u'1022.00 MB'}, u'vda1': {u'sectorsize': 512, u'uuid': u'0c92f976-1be3-45b0-91b7-9ac287522ca3', u'sectors': u'14678016', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': [u'0c92f976-1be3-45b0-91b7-9ac287522ca3']}, u'start': u'2048', u'holders': [], u'size': u'7.00 GB'}, u'vda2': {u'sectorsize': 512, u'uuid': None, u'sectors': u'2', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'start': u'14682110', u'holders': [], u'size': u'1.00 KB'}}}, u'vdb': {u'scheduler_mode': u'', u'rotational': u'1', u'vendor': u'0x1af4', u'sectors': u'2097152', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': []}, u'sas_device_handle': None, u'sas_address': None, u'virtual': 1, u'host': u'SCSI storage controller: Red Hat, Inc Virtio block device', u'sectorsize': u'512', u'removable': u'0', u'support_discard': u'0', u'model': None, u'size': u'1.00 GB', u'holders': [], u'partitions': {u'vdb1': {u'sectorsize': 512, u'uuid': u'33bf4881-0ad0-4416-a80e-8523315b7ddc', u'sectors': u'2095104', u'links': {u'masters': [], u'labels': [], u'ids': [], u'uuids': [u'33bf4881-0ad0-4416-a80e-8523315b7ddc']}, u'start': u'2048', u'holders': [], u'size': u'1023.00 MB'}}}}, u'ansible_user_uid': 0, u'ansible_memory_mb': {u'real': {u'total': 2001, u'free': 23, u'used': 1978}, u'swap': {u'cached': 73, u'total': 1021, u'used': 310, u'free': 711}, u'nocache': {u'used': 1851, u'free': 150}}, u'ansible_distribution': u'Ubuntu', u'ansible_user_dir': u'/root', u'ansible_env': {u'LANG': u'en_US.UTF-8', u'TERM': u'xterm-256color', u'SHELL': u'/bin/bash', u'XDG_RUNTIME_DIR': u'/run/user/0', u'SHLVL': u'1', u'SSH_TTY': u'/dev/pts/1', u'PWD': u'/root', u'PATH': u'/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games', u'SSH_CLIENT': u'172.10.30.238 49414 22', u'LOGNAME': u'root', u'USER': u'root', u'MAIL': u'/var/mail/root', u'HOME': u'/root', u'SSH_CONNECTION': u'172.10.30.238 49414 172.10.30.228 22', u'XDG_SESSION_ID': u'2', u'_': u'/bin/sh'}, u'ansible_distribution_major_version': u'14', u'module_setup': True, u'ansible_processor_count': 1, u'ansible_hostname': u'u1', u'ansible_processor_vcpus': 1, u'ansible_swaptotal_mb': 1021, u'ansible_lsb': {u'release': u'14.04', u'major_release': u'14', u'codename': u'trusty', u'id': u'Ubuntu', u'description': u'Ubuntu 14.04.4 LTS'}, u'ansible_real_group_id': 0, u'ansible_bios_date': u'01/01/2011', u'ansible_all_ipv6_addresses': [u'fe80::5054:ff:feb0:4820'], u'ansible_interfaces': [u'lo', u'eth0'], u'ansible_uptime_seconds': 582, u'ansible_machine_id': u'5ac91a6ec9de72d3736f8d73583c0f24', u'ansible_ssh_host_key_rsa_public': u'AAAAB3NzaC1yc2EAAAADAQABAAABAQDns442vQmhOGiHAjreat9mVsuMX8Ja4jV0Vbu6HJN9/lXRpmePTf0IJGrWTsnoU13u07AAtCcZ0+2OM9SdexkfyuJOCANuZAUCJII1nDzkC6DVJD8iIbPfEecBV0h1mDnu+HZq58VpqIR7GJOz2Gh5CRbafuBWNBA5Mv85Gzn2G4sdfqTQGripQW3RaPvl/U4ZU8mFaRycgVLyxhUwJX6N7n9y3mZaHv54RwGKHDMONypkDjbbf8lRDsVAmHRbBitSc1LojXtCBFaFO7Bxfj1Q9UswbCl0BJvRGc/CzDMXTeVTOKEFjFdpd1KLRDolngKq4HYsWEMGq91QaGbjCD1B', u'ansible_machine': u'x86_64', u'ansible_user_gecos': u'root', u'ansible_system_capabilities_enforced': u'True', u'ansible_python': {u'executable': u'/usr/bin/python', u'version': {u'micro': 6, u'major': 2, u'releaselevel': u'final', u'serial': 0, u'minor': 7}, u'type': u'CPython', u'has_sslcontext': False, u'version_info': [2, 7, 6, u'final', 0]}, u'ansible_processor_threads_per_core': 1, u'ansible_is_chroot': False, u'ansible_user_gid': 0, u'ansible_eth0': {u'macaddress': u'52:54:00:b0:48:20', u'features': {u'tx_checksum_ipv4': u'off [fixed]', u'generic_receive_offload': u'on', u'tx_checksum_ipv6': u'off [fixed]', u'tx_scatter_gather_fraglist': u'off [fixed]', u'rx_all': u'off [fixed]', u'highdma': u'on [fixed]', u'rx_fcs': u'off [fixed]', u'tx_lockless': u'off [fixed]', u'tx_tcp_ecn_segmentation': u'on', u'tx_gso_robust': u'on [fixed]', u'tx_ipip_segmentation': u'off [fixed]', u'tx_checksumming': u'on', u'vlan_challenged': u'off [fixed]', u'loopback': u'off [fixed]', u'fcoe_mtu': u'off [fixed]', u'tx_checksum_sctp': u'off [fixed]', u'tx_vlan_stag_hw_insert': u'off [fixed]', u'rx_vlan_stag_hw_parse': u'off [fixed]', u'tx_nocache_copy': u'off', u'rx_vlan_stag_filter': u'off [fixed]', u'large_receive_offload': u'off [fixed]', u'tx_checksum_ip_generic': u'on', u'rx_checksumming': u'on [fixed]', u'tx_tcp_segmentation': u'on', u'tx_fcoe_segmentation': u'off [fixed]', u'busy_poll': u'on [fixed]', u'generic_segmentation_offload': u'on', u'tx_udp_tnl_segmentation': u'off [fixed]', u'tcp_segmentation_offload': u'on', u'l2_fwd_offload': u'off [fixed]', u'rx_vlan_offload': u'off [fixed]', u'ntuple_filters': u'off [fixed]', u'rx_vlan_filter': u'on [fixed]', u'tx_tcp6_segmentation': u'on', u'udp_fragmentation_offload': u'on', u'scatter_gather': u'on', u'tx_sit_segmentation': u'off [fixed]', u'tx_checksum_fcoe_crc': u'off [fixed]', u'tx_scatter_gather': u'on', u'netns_local': u'off [fixed]', u'tx_vlan_offload': u'off [fixed]', u'receive_hashing': u'off [fixed]', u'tx_gre_segmentation': u'off [fixed]'}, u'pciid': u'virtio0', u'mtu': 1500, u'active': True, u'promisc': False, u'timestamping': [u'tx_software', u'rx_software', u'software'], u'ipv4': {u'broadcast': u'172.10.30.255', u'netmask': u'255.255.255.0', u'network': u'172.10.30.0', u'address': u'172.10.30.228'}, u'ipv6': [{u'scope': u'link', u'prefix': u'64', u'address': u'fe80::5054:ff:feb0:4820'}], u'device': u'eth0', u'type': u'ether', u'hw_timestamp_filters': []}, u'ansible_ssh_host_key_ed25519_public': u'AAAAC3NzaC1lZDI1NTE5AAAAIEfNa9aCyXuWcnokIi2AdpiNc2Qkak3VgYORGspoj+MR', u'ansible_system': u'Linux', u'ansible_user_shell': u'/bin/bash', u'ansible_system_capabilities': [u'cap_chown', u'cap_dac_override', u'cap_dac_read_search', u'cap_fowner', u'cap_fsetid', u'cap_kill', u'cap_setgid', u'cap_setuid', u'cap_setpcap', u'cap_linux_immutable', u'cap_net_bind_service', u'cap_net_broadcast', u'cap_net_admin', u'cap_net_raw', u'cap_ipc_lock', u'cap_ipc_owner', u'cap_sys_module', u'cap_sys_rawio', u'cap_sys_chroot', u'cap_sys_ptrace', u'cap_sys_pacct', u'cap_sys_admin', u'cap_sys_boot', u'cap_sys_nice', u'cap_sys_resource', u'cap_sys_time', u'cap_sys_tty_config', u'cap_mknod', u'cap_lease', u'cap_audit_write', u'cap_audit_control', u'cap_setfcap', u'cap_mac_override', u'cap_mac_admin', u'cap_syslog', u'cap_wake_alarm', u'cap_block_suspend', u'37+ep'], u'ansible_ssh_host_key_dsa_public': u'AAAAB3NzaC1kc3MAAACBAPkoaJoV8NXZRjlIrRaTLO2CTm5JdbgYu+eiCH3JRt6ItVqjbxImIv1dcXlPlgNddW+a0JnyQbLo/tPVtBN7a7RpICIo0kUmjhLieRXcmqS/TeOM8OJ4Tu9CUbzSnhdNRgrWvEGrayh77qW0hLObtikWsh5JPPFFirWO9gUqZiB/AAAAFQC4uSEIquayeRLYhvl9huLFeYP7LQAAAIEAqaWuPAYl774ABSNVnlrYG6cOW4JZJBA6PwaZqZcrzKCYu0XxBeUrsJecBO3dIyquyh6z6tokeGvFkzK5keQrLpo5LAESSDmvGcTzHxCNLN4wZ6X6K5SCh+sKxhoJKPKsM3TV++m7s9msZnzfDS2UZNmYcMXTQHC7B20g5WBB+BoAAACBALdpyGEh1WRZ7hZj3/8IhqFpERIIJI976HWbFmgHjDrvvVcLH37dmp67n8WmhKCkV8hzPyQD65xqHSljnwUKZSI7hfAMONiUW7O8fY+V5rDpwrJ0KN3y+H9II/6Z5fKRmqrpdRbma1PMA0LYMnTU56SfSaplGI8IkMeQYjVjI4z7', u'ansible_kernel': u'4.2.0-27-generic', u'ansible_nodename': u'u1'}} Wednesday 11 July 2018 11:41:21 +0800 (0:00:10.267) 0:00:10.345 ******** WARNING:root:===v2_runner_on_ok===host=172.10.30.228===result={'_ansible_parsed': True, u'src': u'/root/.ansible/tmp/ansible-tmp-1531280481.97-162371082681443/source', u'changed': True, u'group': u'root', u'uid': 0, u'dest': u'/mnt/cross.rar', u'checksum': u'7c8925a6cafdb9fdae974cd27ed198f58a071386', u'md5sum': u'540ad24b57f299fe34856bcea7a0ce2f', u'owner': u'root', u'state': u'file', u'gid': 0, u'mode': u'0644', u'invocation': {u'module_args': {u'directory_mode': None, u'force': True, u'remote_src': None, u'owner': None, u'follow': False, u'local_follow': None, u'group': None, u'unsafe_writes': None, u'setype': None, u'content': None, u'serole': None, u'dest': u'/mnt/cross.rar', u'selevel': None, u'original_basename': u'cross.rar', u'regexp': None, u'validate': None, u'src': u'/root/.ansible/tmp/ansible-tmp-1531280481.97-162371082681443/source', u'checksum': u'7c8925a6cafdb9fdae974cd27ed198f58a071386', u'seuser': None, u'delimiter': None, u'mode': None, u'attributes': None, u'backup': True}}, 'diff': [], u'size': 152151, '_ansible_no_log': False} to retry, use: --limit @/root/temp/main.retry Wednesday 11 July 2018 11:41:23 +0800 (0:00:02.060) 0:00:12.405 ******** =============================================================================== Gathering Facts -------------------------------------------------------- 10.27s test copy --------------------------------------------------------------- 2.06s
一个另外的callback例子
class ResultsCollector(CallbackBase): def __init__(self,*args,**kwargs): super(ResultsCollector, self).__init__(display=None) self.result_ok=json.dumps({}) self.result_failed=json.dumps({}) self.result_unreach=json.dumps({}) self.host_ok=[] self.host_failed=[] self.host_unreach=[] def v2_runner_on_ok(self, result): print "ok" host = result._host.get_name() self.runner_on_ok(host, result._result) self.result_ok=json.dumps({host:result._result},indent=4) self.host_ok.append(host) # print("ok: %s" %self.host_ok) print (result._host,result._result.get('cmd'),result._result.get('stdout'),result._result.get("msg")) def v2_runner_on_failed(self, result, ignore_errors=False): print "failed" host = result._host.get_name() self.runner_on_ok(host, result._result) self.result_failed = json.dumps({host: result._result},indent=4) self.host_failed.append(host) # print("failed: %s" %self.host_failed) print result._host,result._result.get('cmd') def v2_runner_on_unreachable(self, result): print("unreached") host = result._host.get_name() self.runner_on_ok(host, result._result) self.result_unreach = json.dumps({host: result._result},indent=4) self.host_unreach.append(host) # print("unreacheable: %s" %self.host_unreach) print result._host,result._result
自己写的一个ansibleapi:
#-*- encoding: utf-8 #!/usr/bin/python import json import shutil import os from collections import namedtuple from ansible.parsing.dataloader import DataLoader from ansible.vars.manager import VariableManager from ansible.inventory.manager import InventoryManager from ansible.playbook.play import Play from ansible.executor.task_queue_manager import TaskQueueManager from tempfile import NamedTemporaryFile from ansible.plugins.callback import CallbackBase import ansible.constants as C #自定义回调 class ResultCallback(CallbackBase): def __init__(self, *args): super(ResultCallback, self).__init__(display=None) self.status_ok = json.dumps({}) self.status_fail = json.dumps({}) self.status_unreachable = json.dumps({}) self.host_ok = {} self.host_failed = {} self.host_unreachable = {} def v2_runner_on_ok(self, result): host = result._host.get_name() self.runner_on_ok(host, result._result) self.status_ok=json.dumps({host:result._result},indent=4) self.host_ok[host] = result # print self.status_ok; def v2_runner_on_failed(self, result, ignore_errors=False): host = result._host.get_name() self.runner_on_failed(host, result._result, ignore_errors) self.status_fail=json.dumps({host:result._result},indent=4) self.host_failed[host] = result # print self.status_fail def v2_runner_on_unreachable(self, result): host = result._host.get_name() self.runner_on_unreachable(host, result._result) self.status_unreachable=json.dumps({host:result._result},indent=4) self.host_unreachable[host] = result # print self.status_unreachable class Ansible_Api(object): """ This is a General object for parallel execute modules. 默认使用自定义的callback. """ def __init__(self,hosts="localhost,",use_module="command",myagrs=None,default_callback=False): self.hosts = hosts self.password = {} self.use_module = use_module self.myargs = myagrs self.default_callback = default_callback def RunApi(self): Option = namedtuple('Option',['listhosts','syntaxcheck','connection','module_path','forks', 'private_key_file','ssh_common_args','ssh_extra_args','sftp_extra_args', 'scp_extra_args','become','become_method','become_user','verbose', 'check','askbecomepass','asksupass','asksudopass','askpass','askvaultpass','diff']) option = Option(listhosts=False,syntaxcheck=True,connection="smart",module_path=None,forks=8, private_key_file=None,ssh_common_args=None,ssh_extra_args=None,sftp_extra_args=None, scp_extra_args=None,become=None,become_method=None,become_user=None,verbose=None, check=False,askbecomepass=None,askpass=None,asksudopass=None,asksupass=None,askvaultpass=None,diff=False) result_callback = ResultCallback() loader = DataLoader() inventory = InventoryManager(loader=loader, sources=self.hosts) variable_manager = VariableManager(loader=loader, inventory=inventory) #创建play的数据结构,就相当于是一个平常用的yml文件(也相当于一个ansible命令)。 if self.myargs is not None: play_source= dict( name = "ansible Play", hosts = self.hosts, gather_facts = 'no', tasks = [ dict(action=dict(module=self.use_module,args=self.myargs)), # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ] ) else: play_source = dict( name="ansible Play", hosts=self.hosts, gather_facts='no', tasks=[ dict(action=dict(module=self.use_module), register='shell_out'), # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ] ) #创建play对象,也将自动创建task对象。 play = Play().load(play_source,variable_manager=variable_manager,loader=loader) tqm=None try: if self.default_callback: tqm = TaskQueueManager( inventory = inventory, variable_manager = variable_manager, loader = loader, options= option, passwords = self.password, # stdout_callback=result_callback, stdout_callback="default", ) else: tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, options=option, passwords=self.password, stdout_callback=result_callback, # stdout_callback="default", ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() shutil.rmtree(C.DEFAULT_LOCAL_TMP,True) return result_callback def gather_result(self): re_callback = self.RunApi() results_raw = {} results_raw['success'] = {} results_raw['failed'] = {} results_raw['unreachable'] = {} for host, result in re_callback.host_ok.items(): results_raw['success'][host] = json.dumps(result._result) for host, result in re_callback.host_failed.items(): results_raw['failed'][host] = result._result['msg'] for host, result in re_callback.host_unreachable.items(): results_raw['unreachable'][host] = result._result['msg'] return results_raw # def format_result(self): # result_all = self.gather_result() # print ("""\033[ success ====================> # %s # \033[1m""") %result_all['success'] if __name__ == "__main__": a = Ansible_Api("172.10.30.228,172.10.30.254,121.41.77.35",use_module="copy",myagrs="src=/mnt/1.txt dest=/mnt",default_callback=False) print a.gather_result()
改进后版本:
#-*- encoding: utf-8 #!/usr/bin/python import json import shutil import os from collections import namedtuple from ansible.parsing.dataloader import DataLoader from ansible.vars.manager import VariableManager from ansible.inventory.manager import InventoryManager from ansible.playbook.play import Play from ansible.executor.task_queue_manager import TaskQueueManager from tempfile import NamedTemporaryFile from ansible.plugins.callback import CallbackBase import ansible.constants as C #自定义回调 class ResultCallback(CallbackBase): def __init__(self, *args): super(ResultCallback, self).__init__(display=None) self.status_ok = json.dumps({}) self.status_fail = json.dumps({}) self.status_unreachable = json.dumps({}) self.host_ok = {} self.host_failed = {} self.host_unreachable = {} def v2_runner_on_ok(self, result): host = result._host.get_name() self.runner_on_ok(host, result._result) self.status_ok=json.dumps({host:result._result},indent=4) self.host_ok[host] = result # print self.status_ok; def v2_runner_on_failed(self, result, ignore_errors=False): host = result._host.get_name() self.runner_on_failed(host, result._result, ignore_errors) self.status_fail=json.dumps({host:result._result},indent=4) self.host_failed[host] = result # print self.status_fail def v2_runner_on_unreachable(self, result): host = result._host.get_name() self.runner_on_unreachable(host, result._result) self.status_unreachable=json.dumps({host:result._result},indent=4) self.host_unreachable[host] = result # print self.status_unreachable class Ansible_Api(object): """ This is a General object for parallel execute modules. 默认使用自定义的callback. """ def __init__(self,hosts="localhost,",use_module="command",myagrs=None, remote_user="root",**kwargs): """ :param hosts: 执行ansible命令的主机 :param use_module: ansible命令用的模块 :param myagrs: ansible 命令的参数 :param remote_user: ssh时的用户,如果远程主机没有该user,或者该user没有添加 免密码登录,都会出错。 默认用root :param kwargs: 用来接收其它的option参数 """ self.hosts = hosts self.password = {} self.use_module = use_module self.myargs = myagrs self.remote_user = remote_user Option = namedtuple('Option', ['listhosts', 'syntaxcheck', 'connection', 'module_path', 'forks', 'private_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', 'verbose', 'check', 'askbecomepass', 'asksupass', 'asksudopass', 'askpass', 'askvaultpass', 'diff', "remote_user"]) self.option = Option(listhosts=False, syntaxcheck=True, connection="smart", module_path=None, forks=8, private_key_file=None, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=None, become_method=None, become_user=None, verbose=None, check=False, askbecomepass=None, askpass=None, asksudopass=None, asksupass=None, askvaultpass=None, diff=False, remote_user=self.remote_user) self.result_callback = ResultCallback() self.loader = DataLoader() self.inventory = InventoryManager(loader=self.loader, sources=self.hosts) self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) def RunApi(self): #创建play的数据结构,就相当于是一个平常用的yml文件(也相当于一个ansible命令)。 if self.myargs is not None: play_source= dict( name = "ansible Play", hosts = self.hosts, gather_facts = 'no', tasks = [ dict(action=dict(module=self.use_module,args=self.myargs)), # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ] ) else: play_source = dict( name="ansible Play", hosts=self.hosts, gather_facts='no', tasks=[ dict(action=dict(module=self.use_module), register='shell_out'), # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))) ] ) #创建play对象,也将自动创建task对象。 play = Play().load(play_source,variable_manager=self.variable_manager,loader=self.loader) tqm=None try: tqm = TaskQueueManager( inventory = self.inventory, variable_manager = self.variable_manager, loader = self.loader, options= self.option, passwords = self.password, stdout_callback=self.result_callback, # stdout_callback="default", ) result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() shutil.rmtree(C.DEFAULT_LOCAL_TMP,True) return self.result_callback def gather_result(self): """ 返回执行结果后的整理集合. :return: """ re_callback = self.RunApi() results_raw = {} results_raw['success'] = {} results_raw['failed'] = {} results_raw['unreachable'] = {} for host, result in re_callback.host_ok.items(): results_raw['success'][host] = json.dumps(result._result) for host, result in re_callback.host_failed.items(): results_raw['failed'][host] = result._result['msg'] for host, result in re_callback.host_unreachable.items(): results_raw['unreachable'][host] = result._result['msg'] return results_raw def ExecAnsible(hosts="localhost,",use_module="setup",myagrs=None, remote_user="root",**kwargs): re = Ansible_Api(hosts=hosts,use_module=use_module,myagrs=myagrs,remote_user=remote_user, kwargs=kwargs).gather_result() return re if __name__ == "__main__": # a = Ansible_Api("172.10.30.228,172.10.30.254,121.41.77.35",use_module="copy",myagrs="src=/mnt/1.txt dest=/mnt owner=test", # remote_user="test") # print a.gather_result() hosts = ["172.10.30.228,172.10.30.254"] re=ExecAnsible(hosts=hosts,use_module="copy",myagrs="src=/mnt/1.txt dest=/mnt owner=test", ) print re["failed"] print re["success"],type(re['success']) print re['unreachable']