ansible_api_2.0

参考: 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']

   
改进后版本

猜你喜欢

转载自www.cnblogs.com/yitianyouyitian/p/9263236.html
今日推荐