返回总目录页

ansible api调用及二次封装详解

 

ansible 2.7调用

程序

import json
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 ansible.plugins.callback import CallbackBase


class ResultsCollector(CallbackBase):
    """重构执行结果"""
    def __init__(self, *args, **kwargs):
        super(ResultsCollector, self).__init__(*args, **kwargs)
        self.host_ok = {}
        self.host_unreachable = {}
        self.host_failed = {}

    def v2_runner_on_unreachable(self, result, *args, **kwargs):
        """不可达"""
        self.host_unreachable[result._host.get_name()] = result

    def v2_runner_on_ok(self, result, *args, **kwargs):
        """执行成功"""
        self.host_ok[result._host.get_name()] = result

    def v2_runner_on_failed(self, result, *args, **kwargs):
        """执行失败"""
        self.host_failed[result._host.get_name()] = result


def run_ansible(module_name,module_args,host_list,option_dict):
    # 初始化需要的对象
    Options = namedtuple('Options',
                         ['connection', 'module_path', 'forks', 'become',
                          'become_method', 'private_key_file','become_user',
                          'remote_user', 'check', 'diff']
                         )
    #负责查找和读取yaml、json和ini文件
    loader = DataLoader()

    options = Options(connection='ssh', module_path=None, forks=5, become=option_dict['become'],
                      become_method='sudo',private_key_file="/root/.ssh/id_rsa",
                      become_user='root', remote_user=option_dict['remote_user'], check=False, diff=False
                      )

    passwords = dict(vault_pass='secret')

    # 实例化ResultCallback来处理结果
    callback = ResultsCollector()

    # 创建库存(inventory)并传递给VariableManager
    inventory = InventoryManager(loader=loader, sources=['/etc/ansible/hosts'])
    variable_manager = VariableManager(loader=loader, inventory=inventory)

    # 创建任务
    host = ",".join(host_list)
    play_source = dict(
        name="Ansible Play",
        hosts=host,
        gather_facts='no',
        tasks=[
            dict(action=dict(module=module_name, args=module_args), register='shell_out'),
        ]
    )
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)

    # 开始执行
    tqm = None

    tqm = TaskQueueManager(
        inventory=inventory,
        variable_manager=variable_manager,
        loader=loader,
        options=options,
        passwords=passwords,
        stdout_callback=callback,
    )
    result = tqm.run(play)

    result_raw = {'success': {}, 'failed': {}, 'unreachable': {}}

    for host, result in callback.host_ok.items():
        result_raw['success'][host] = result._result['stdout_lines']

    for host, result in callback.host_failed.items():
        result_raw['failed'][host] = result._result['stderr_lines']

    for host, result in callback.host_unreachable.items():
        result_raw['unreachable'][host] = result._result["msg"]

    return json.dumps(result_raw, indent=4)


if __name__ == "__main__":
    option_dict={"become":True,"remote_user":"opadmin"}
    module_name = 'shell'
    module_args = "hostname"
    host_list = ['10.0.0.131','10.0.0.132']
    ret = run_ansible(module_name,module_args,host_list,option_dict)
    print(ret)

运行结果:

[root@mcw1 ~]$ python3 runapi.py 
{
    "success": {},
    "failed": {},
    "unreachable": {
        "10.0.0.132": "Failed to connect to the host via ssh: opadmin@10.0.0.132: Permission denied (publickey,password).\r\n",
        "10.0.0.131": "Failed to connect to the host via ssh: opadmin@10.0.0.131: Permission denied (publickey,password,keyboard-interactive).\r\n"
    }
}
[root@mcw1 ~]$ 

又上面程序可知,是用opadmin用户连接,而我并没有这个用户,改成root当前连接用户就行了

 

执行结果如下:

[root@mcw1 ~]$ python3 runapi.py 
{
    "success": {
        "10.0.0.132": [
            "mcw2"
        ],
        "10.0.0.131": [
            "mcw1"
        ]
    },
    "failed": {},
    "unreachable": {}
}

新增主机133,但是这台主机并没有运行,肯定连不上

[root@mcw1 ~]$ python3 runapi.py 
 [WARNING]: Could not match supplied host pattern, ignoring: 10.0.0.133

{
    "success": {
        "10.0.0.132": [
            "mcw2"
        ],
        "10.0.0.131": [
            "mcw1"
        ]
    },
    "failed": {},
    "unreachable": {}
}

 

打印结果:

for host, result in callback.host_ok.items():
  result_raw['success'][host] = result._result['stdout_lines']
  print('chenggongde',result)


for host, result in callback.host_failed.items():
  result_raw['failed'][host] = result._result['stderr_lines']
  print('shibaide',result)

 


[root@mcw1 ~]$ python3 runapi.py [WARNING]: Could not match supplied host pattern, ignoring: 10.0.0.133 chenggongde <ansible.executor.task_result.TaskResult object at 0x7f39929c5828> chenggongde <ansible.executor.task_result.TaskResult object at 0x7f399215ad30> { "success": { "10.0.0.132": [ "mcw2" ], "10.0.0.131": [ "mcw1" ] }, "failed": {}, "unreachable": {} } [root@mcw1 ~]$ vim runapi.py [root@mcw1 ~]$ [root@mcw1 ~]$

for host, result in callback.host_ok.items():
  result_raw['success'][host] = result._result['stdout_lines']
  print('chenggongde',result._result)


for host, result in callback.host_failed.items():
  result_raw['failed'][host] = result._result['stderr_lines']
  print('shibaide',result.result)


[root@mcw1 ~]$ python3 runapi.py 
 [WARNING]: Could not match supplied host pattern, ignoring: 10.0.0.133

chenggongde {'changed': True, 'end': '2021-12-14 11:43:50.453528', 'stdout': 'mcw2', 'cmd': 'hostname', 'rc': 0, 'start': '2021-12-14 11:43:50.438420', 'stderr': '', 'delta': '0:00:00.015108', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': 'hostname', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': ['mcw2'], 'stderr_lines': [], '_ansible_no_log': False}
chenggongde {'changed': True, 'end': '2021-12-14 03:43:49.826931', 'stdout': 'mcw1', 'cmd': 'hostname', 'rc': 0, 'start': '2021-12-14 03:43:49.820276', 'stderr': '', 'delta': '0:00:00.006655', 'invocation': {'module_args': {'creates': None, 'executable': None, '_uses_shell': True, '_raw_params': 'hostname', 'removes': None, 'argv': None, 'warn': True, 'chdir': None, 'stdin': None}}, '_ansible_parsed': True, 'stdout_lines': ['mcw1'], 'stderr_lines': [], '_ansible_no_log': False}
{
    "success": {
        "10.0.0.132": [
            "mcw2"
        ],
        "10.0.0.131": [
            "mcw1"
        ]
    },
    "failed": {},
    "unreachable": {}
}

 成功返回结果JSON格式

{
    'changed': True,
    'end': '2021-12-14 11:43:50.453528',
    'stdout': 'mcw2',
    'cmd': 'hostname',
    'rc': 0,
    'start': '2021-12-14 11:43:50.438420',
    'stderr': '',
    'delta': '0:00:00.015108',
    'invocation': {
        'module_args': {
            'creates': None,
            'executable': None,
            '_uses_shell': True,
            '_raw_params': 'hostname',
            'removes': None,
            'argv': None,
            'warn': True,
            'chdir': None,
            'stdin': None
        }
    },
    '_ansible_parsed': True,
    'stdout_lines': ['mcw2'],
    'stderr_lines': [],
    '_ansible_no_log': False
}
成功返回结果

ansible的setup模块返回信息

[root@mcw1 ~]$ ansible 10.0.0.132 -m setup
10.0.0.132 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "172.16.1.132", 
            "10.0.0.132"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::20c:29ff:fe01:a8d1", 
            "fe80::20c:29ff:fe01:a8c7"
        ], 
        "ansible_apparmor": {
            "status": "disabled"
        }, 
        "ansible_architecture": "x86_64", 
        "ansible_bios_date": "07/02/2015", 
        "ansible_bios_version": "6.00", 
        "ansible_cmdline": {
            "BOOT_IMAGE": "/vmlinuz-3.10.0-693.el7.x86_64", 
            "LANG": "en_US.UTF-8", 
            "crashkernel": "auto", 
            "quiet": true, 
            "rhgb": true, 
            "ro": true, 
            "root": "UUID=a6a0174b-0f9f-4b72-a404-439c25a15ec9"
        }, 
        "ansible_date_time": {
            "date": "2021-12-14", 
            "day": "14", 
            "epoch": "1639454188", 
            "hour": "11", 
            "iso8601": "2021-12-14T03:56:28Z", 
            "iso8601_basic": "20211214T115628396754", 
            "iso8601_basic_short": "20211214T115628", 
            "iso8601_micro": "2021-12-14T03:56:28.396754Z", 
            "minute": "56", 
            "month": "12", 
            "second": "28", 
            "time": "11:56:28", 
            "tz": "CST", 
            "tz_offset": "+0800", 
            "weekday": "Tuesday", 
            "weekday_number": "2", 
            "weeknumber": "50", 
            "year": "2021"
        }, 
        "ansible_default_ipv4": {
            "address": "10.0.0.132", 
            "alias": "ens33", 
            "broadcast": "10.0.0.255", 
            "gateway": "10.0.0.2", 
            "interface": "ens33", 
            "macaddress": "00:0c:29:01:a8:c7", 
            "mtu": 1500, 
            "netmask": "255.255.255.0", 
            "network": "10.0.0.0", 
            "type": "ether"
        }, 
        "ansible_default_ipv6": {}, 
        "ansible_device_links": {
            "ids": {
                "sr0": [
                    "ata-VMware_Virtual_IDE_CDROM_Drive_10000000000000000001"
                ]
            }, 
            "labels": {
                "sr0": [
                    "CentOS\\x207\\x20x86_64"
                ]
            }, 
            "masters": {}, 
            "uuids": {
                "sda1": [
                    "20f697d6-9ca0-4b9e-9f20-56325684f2ca"
                ], 
                "sda2": [
                    "6042e061-f29b-4ac1-9f32-87980ddf0e1f"
                ], 
                "sda3": [
                    "a6a0174b-0f9f-4b72-a404-439c25a15ec9"
                ], 
                "sr0": [
                    "2017-09-06-10-51-00-00"
                ]
            }
        }, 
        "ansible_devices": {
            "sda": {
                "holders": [], 
                "host": "SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)", 
                "links": {
                    "ids": [], 
                    "labels": [], 
                    "masters": [], 
                    "uuids": []
                }, 
                "model": "VMware Virtual S", 
                "partitions": {
                    "sda1": {
                        "holders": [], 
                        "links": {
                            "ids": [], 
                            "labels": [], 
                            "masters": [], 
                            "uuids": [
                                "20f697d6-9ca0-4b9e-9f20-56325684f2ca"
                            ]
                        }, 
                        "sectors": "1015808", 
                        "sectorsize": 512, 
                        "size": "496.00 MB", 
                        "start": "2048", 
                        "uuid": "20f697d6-9ca0-4b9e-9f20-56325684f2ca"
                    }, 
                    "sda2": {
                        "holders": [], 
                        "links": {
                            "ids": [], 
                            "labels": [], 
                            "masters": [], 
                            "uuids": [
                                "6042e061-f29b-4ac1-9f32-87980ddf0e1f"
                            ]
                        }, 
                        "sectors": "1587200", 
                        "sectorsize": 512, 
                        "size": "775.00 MB", 
                        "start": "1017856", 
                        "uuid": "6042e061-f29b-4ac1-9f32-87980ddf0e1f"
                    }, 
                    "sda3": {
                        "holders": [], 
                        "links": {
                            "ids": [], 
                            "labels": [], 
                            "masters": [], 
                            "uuids": [
                                "a6a0174b-0f9f-4b72-a404-439c25a15ec9"
                            ]
                        }, 
                        "sectors": "39337984", 
                        "sectorsize": 512, 
                        "size": "18.76 GB", 
                        "start": "2605056", 
                        "uuid": "a6a0174b-0f9f-4b72-a404-439c25a15ec9"
                    }
                }, 
                "removable": "0", 
                "rotational": "1", 
                "sas_address": null, 
                "sas_device_handle": null, 
                "scheduler_mode": "deadline", 
                "sectors": "41943040", 
                "sectorsize": "512", 
                "size": "20.00 GB", 
                "support_discard": "0", 
                "vendor": "VMware,", 
                "virtual": 1
            }, 
            "sr0": {
                "holders": [], 
                "host": "IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)", 
                "links": {
                    "ids": [
                        "ata-VMware_Virtual_IDE_CDROM_Drive_10000000000000000001"
                    ], 
                    "labels": [
                        "CentOS\\x207\\x20x86_64"
                    ], 
                    "masters": [], 
                    "uuids": [
                        "2017-09-06-10-51-00-00"
                    ]
                }, 
                "model": "VMware IDE CDR10", 
                "partitions": {}, 
                "removable": "1", 
                "rotational": "1", 
                "sas_address": null, 
                "sas_device_handle": null, 
                "scheduler_mode": "cfq", 
                "sectors": "8830976", 
                "sectorsize": "2048", 
                "size": "4.21 GB", 
                "support_discard": "0", 
                "vendor": "NECVMWar", 
                "virtual": 1
            }
        }, 
        "ansible_distribution": "CentOS", 
        "ansible_distribution_file_parsed": true, 
        "ansible_distribution_file_path": "/etc/redhat-release", 
        "ansible_distribution_file_variety": "RedHat", 
        "ansible_distribution_major_version": "7", 
        "ansible_distribution_release": "Core", 
        "ansible_distribution_version": "7.4", 
        "ansible_dns": {
            "nameservers": [
                "2.5.5.5", 
                "2.6.6.6", 
                "223.5.5.5", 
                "223.6.6.6"
            ]
        }, 
        "ansible_domain": "", 
        "ansible_effective_group_id": 0, 
        "ansible_effective_user_id": 0, 
        "ansible_ens33": {
            "active": true, 
            "device": "ens33", 
            "features": {
                "busy_poll": "off [fixed]", 
                "fcoe_mtu": "off [fixed]", 
                "generic_receive_offload": "on", 
                "generic_segmentation_offload": "on", 
                "highdma": "off [fixed]", 
                "hw_tc_offload": "off [fixed]", 
                "l2_fwd_offload": "off [fixed]", 
                "large_receive_offload": "off [fixed]", 
                "loopback": "off [fixed]", 
                "netns_local": "off [fixed]", 
                "ntuple_filters": "off [fixed]", 
                "receive_hashing": "off [fixed]", 
                "rx_all": "off", 
                "rx_checksumming": "off", 
                "rx_fcs": "off", 
                "rx_vlan_filter": "on [fixed]", 
                "rx_vlan_offload": "on", 
                "rx_vlan_stag_filter": "off [fixed]", 
                "rx_vlan_stag_hw_parse": "off [fixed]", 
                "scatter_gather": "on", 
                "tcp_segmentation_offload": "on", 
                "tx_checksum_fcoe_crc": "off [fixed]", 
                "tx_checksum_ip_generic": "on", 
                "tx_checksum_ipv4": "off [fixed]", 
                "tx_checksum_ipv6": "off [fixed]", 
                "tx_checksum_sctp": "off [fixed]", 
                "tx_checksumming": "on", 
                "tx_fcoe_segmentation": "off [fixed]", 
                "tx_gre_csum_segmentation": "off [fixed]", 
                "tx_gre_segmentation": "off [fixed]", 
                "tx_gso_partial": "off [fixed]", 
                "tx_gso_robust": "off [fixed]", 
                "tx_ipip_segmentation": "off [fixed]", 
                "tx_lockless": "off [fixed]", 
                "tx_mpls_segmentation": "off [fixed]", 
                "tx_nocache_copy": "off", 
                "tx_scatter_gather": "on", 
                "tx_scatter_gather_fraglist": "off [fixed]", 
                "tx_sctp_segmentation": "off [fixed]", 
                "tx_sit_segmentation": "off [fixed]", 
                "tx_tcp6_segmentation": "off [fixed]", 
                "tx_tcp_ecn_segmentation": "off [fixed]", 
                "tx_tcp_mangleid_segmentation": "off", 
                "tx_tcp_segmentation": "on", 
                "tx_udp_tnl_csum_segmentation": "off [fixed]", 
                "tx_udp_tnl_segmentation": "off [fixed]", 
                "tx_vlan_offload": "on [fixed]", 
                "tx_vlan_stag_hw_insert": "off [fixed]", 
                "udp_fragmentation_offload": "off [fixed]", 
                "vlan_challenged": "off [fixed]"
            }, 
            "hw_timestamp_filters": [], 
            "ipv4": {
                "address": "10.0.0.132", 
                "broadcast": "10.0.0.255", 
                "netmask": "255.255.255.0", 
                "network": "10.0.0.0"
            }, 
            "ipv6": [
                {
                    "address": "fe80::20c:29ff:fe01:a8c7", 
                    "prefix": "64", 
                    "scope": "link"
                }
            ], 
            "macaddress": "00:0c:29:01:a8:c7", 
            "module": "e1000", 
            "mtu": 1500, 
            "pciid": "0000:02:01.0", 
            "promisc": false, 
            "speed": 1000, 
            "timestamping": [
                "tx_software", 
                "rx_software", 
                "software"
            ], 
            "type": "ether"
        }, 
        "ansible_ens37": {
            "active": true, 
            "device": "ens37", 
            "features": {
                "busy_poll": "off [fixed]", 
                "fcoe_mtu": "off [fixed]", 
                "generic_receive_offload": "on", 
                "generic_segmentation_offload": "on", 
                "highdma": "off [fixed]", 
                "hw_tc_offload": "off [fixed]", 
                "l2_fwd_offload": "off [fixed]", 
                "large_receive_offload": "off [fixed]", 
                "loopback": "off [fixed]", 
                "netns_local": "off [fixed]", 
                "ntuple_filters": "off [fixed]", 
                "receive_hashing": "off [fixed]", 
                "rx_all": "off", 
                "rx_checksumming": "off", 
                "rx_fcs": "off", 
                "rx_vlan_filter": "on [fixed]", 
                "rx_vlan_offload": "on", 
                "rx_vlan_stag_filter": "off [fixed]", 
                "rx_vlan_stag_hw_parse": "off [fixed]", 
                "scatter_gather": "on", 
                "tcp_segmentation_offload": "on", 
                "tx_checksum_fcoe_crc": "off [fixed]", 
                "tx_checksum_ip_generic": "on", 
                "tx_checksum_ipv4": "off [fixed]", 
                "tx_checksum_ipv6": "off [fixed]", 
                "tx_checksum_sctp": "off [fixed]", 
                "tx_checksumming": "on", 
                "tx_fcoe_segmentation": "off [fixed]", 
                "tx_gre_csum_segmentation": "off [fixed]", 
                "tx_gre_segmentation": "off [fixed]", 
                "tx_gso_partial": "off [fixed]", 
                "tx_gso_robust": "off [fixed]", 
                "tx_ipip_segmentation": "off [fixed]", 
                "tx_lockless": "off [fixed]", 
                "tx_mpls_segmentation": "off [fixed]", 
                "tx_nocache_copy": "off", 
                "tx_scatter_gather": "on", 
                "tx_scatter_gather_fraglist": "off [fixed]", 
                "tx_sctp_segmentation": "off [fixed]", 
                "tx_sit_segmentation": "off [fixed]", 
                "tx_tcp6_segmentation": "off [fixed]", 
                "tx_tcp_ecn_segmentation": "off [fixed]", 
                "tx_tcp_mangleid_segmentation": "off", 
                "tx_tcp_segmentation": "on", 
                "tx_udp_tnl_csum_segmentation": "off [fixed]", 
                "tx_udp_tnl_segmentation": "off [fixed]", 
                "tx_vlan_offload": "on [fixed]", 
                "tx_vlan_stag_hw_insert": "off [fixed]", 
                "udp_fragmentation_offload": "off [fixed]", 
                "vlan_challenged": "off [fixed]"
            }, 
            "hw_timestamp_filters": [], 
            "ipv4": {
                "address": "172.16.1.132", 
                "broadcast": "172.16.1.255", 
                "netmask": "255.255.255.0", 
                "network": "172.16.1.0"
            }, 
            "ipv6": [
                {
                    "address": "fe80::20c:29ff:fe01:a8d1", 
                    "prefix": "64", 
                    "scope": "link"
                }
            ], 
            "macaddress": "00:0c:29:01:a8:d1", 
            "module": "e1000", 
            "mtu": 1500, 
            "pciid": "0000:02:05.0", 
            "promisc": false, 
            "speed": 1000, 
            "timestamping": [
                "tx_software", 
                "rx_software", 
                "software"
            ], 
            "type": "ether"
        }, 
        "ansible_env": {
            "HOME": "/root", 
            "LANG": "en_US.UTF-8", 
            "LESSOPEN": "||/usr/bin/lesspipe.sh %s", 
            "LOGNAME": "root", 
            "LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:", 
            "MAIL": "/var/mail/root", 
            "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin", 
            "PWD": "/root", 
            "SHELL": "/bin/bash", 
            "SHLVL": "2", 
            "SSH_CLIENT": "10.0.0.131 45784 22", 
            "SSH_CONNECTION": "10.0.0.131 45784 10.0.0.132 22", 
            "SSH_TTY": "/dev/pts/1", 
            "TERM": "xterm", 
            "USER": "root", 
            "XDG_RUNTIME_DIR": "/run/user/0", 
            "XDG_SESSION_ID": "33", 
            "_": "/usr/bin/python"
        }, 
        "ansible_fibre_channel_wwn": [], 
        "ansible_fips": false, 
        "ansible_form_factor": "Other", 
        "ansible_fqdn": "mcw2", 
        "ansible_hostname": "mcw2", 
        "ansible_hostnqn": "", 
        "ansible_interfaces": [
            "lo", 
            "ens37", 
            "ens33"
        ], 
        "ansible_is_chroot": false, 
        "ansible_iscsi_iqn": "", 
        "ansible_kernel": "3.10.0-693.el7.x86_64", 
        "ansible_kernel_version": "#1 SMP Tue Aug 22 21:09:27 UTC 2017", 
        "ansible_lo": {
            "active": true, 
            "device": "lo", 
            "features": {
                "busy_poll": "off [fixed]", 
                "fcoe_mtu": "off [fixed]", 
                "generic_receive_offload": "on", 
                "generic_segmentation_offload": "on", 
                "highdma": "on [fixed]", 
                "hw_tc_offload": "off [fixed]", 
                "l2_fwd_offload": "off [fixed]", 
                "large_receive_offload": "off [fixed]", 
                "loopback": "on [fixed]", 
                "netns_local": "on [fixed]", 
                "ntuple_filters": "off [fixed]", 
                "receive_hashing": "off [fixed]", 
                "rx_all": "off [fixed]", 
                "rx_checksumming": "on [fixed]", 
                "rx_fcs": "off [fixed]", 
                "rx_vlan_filter": "off [fixed]", 
                "rx_vlan_offload": "off [fixed]", 
                "rx_vlan_stag_filter": "off [fixed]", 
                "rx_vlan_stag_hw_parse": "off [fixed]", 
                "scatter_gather": "on", 
                "tcp_segmentation_offload": "on", 
                "tx_checksum_fcoe_crc": "off [fixed]", 
                "tx_checksum_ip_generic": "on [fixed]", 
                "tx_checksum_ipv4": "off [fixed]", 
                "tx_checksum_ipv6": "off [fixed]", 
                "tx_checksum_sctp": "on [fixed]", 
                "tx_checksumming": "on", 
                "tx_fcoe_segmentation": "off [fixed]", 
                "tx_gre_csum_segmentation": "off [fixed]", 
                "tx_gre_segmentation": "off [fixed]", 
                "tx_gso_partial": "off [fixed]", 
                "tx_gso_robust": "off [fixed]", 
                "tx_ipip_segmentation": "off [fixed]", 
                "tx_lockless": "on [fixed]", 
                "tx_mpls_segmentation": "off [fixed]", 
                "tx_nocache_copy": "off [fixed]", 
                "tx_scatter_gather": "on [fixed]", 
                "tx_scatter_gather_fraglist": "on [fixed]", 
                "tx_sctp_segmentation": "on", 
                "tx_sit_segmentation": "off [fixed]", 
                "tx_tcp6_segmentation": "on", 
                "tx_tcp_ecn_segmentation": "on", 
                "tx_tcp_mangleid_segmentation": "on", 
                "tx_tcp_segmentation": "on", 
                "tx_udp_tnl_csum_segmentation": "off [fixed]", 
                "tx_udp_tnl_segmentation": "off [fixed]", 
                "tx_vlan_offload": "off [fixed]", 
                "tx_vlan_stag_hw_insert": "off [fixed]", 
                "udp_fragmentation_offload": "on", 
                "vlan_challenged": "on [fixed]"
            }, 
            "hw_timestamp_filters": [], 
            "ipv4": {
                "address": "127.0.0.1", 
                "broadcast": "", 
                "netmask": "255.0.0.0", 
                "network": "127.0.0.0"
            }, 
            "ipv6": [
                {
                    "address": "::1", 
                    "prefix": "128", 
                    "scope": "host"
                }
            ], 
            "mtu": 65536, 
            "promisc": false, 
            "timestamping": [
                "rx_software", 
                "software"
            ], 
            "type": "loopback"
        }, 
        "ansible_local": {}, 
        "ansible_lsb": {}, 
        "ansible_machine": "x86_64", 
        "ansible_machine_id": "06fe05f799ee4e959f6d4acfaf48fb73", 
        "ansible_memfree_mb": 708, 
        "ansible_memory_mb": {
            "nocache": {
                "free": 799, 
                "used": 177
            }, 
            "real": {
                "free": 708, 
                "total": 976, 
                "used": 268
            }, 
            "swap": {
                "cached": 0, 
                "free": 774, 
                "total": 774, 
                "used": 0
            }
        }, 
        "ansible_memtotal_mb": 976, 
        "ansible_mounts": [
            {
                "block_available": 97473, 
                "block_size": 4096, 
                "block_total": 126121, 
                "block_used": 28648, 
                "device": "/dev/sda1", 
                "fstype": "xfs", 
                "inode_available": 253625, 
                "inode_total": 253952, 
                "inode_used": 327, 
                "mount": "/boot", 
                "options": "rw,relatime,attr2,inode64,noquota", 
                "size_available": 399249408, 
                "size_total": 516591616, 
                "uuid": "20f697d6-9ca0-4b9e-9f20-56325684f2ca"
            }, 
            {
                "block_available": 4445479, 
                "block_size": 4096, 
                "block_total": 4914688, 
                "block_used": 469209, 
                "device": "/dev/sda3", 
                "fstype": "xfs", 
                "inode_available": 9777400, 
                "inode_total": 9834496, 
                "inode_used": 57096, 
                "mount": "/", 
                "options": "rw,relatime,attr2,inode64,noquota", 
                "size_available": 18208681984, 
                "size_total": 20130562048, 
                "uuid": "a6a0174b-0f9f-4b72-a404-439c25a15ec9"
            }
        ], 
        "ansible_nodename": "mcw2", 
        "ansible_os_family": "RedHat", 
        "ansible_pkg_mgr": "yum", 
        "ansible_proc_cmdline": {
            "BOOT_IMAGE": "/vmlinuz-3.10.0-693.el7.x86_64", 
            "LANG": "en_US.UTF-8", 
            "crashkernel": "auto", 
            "quiet": true, 
            "rhgb": true, 
            "ro": true, 
            "root": "UUID=a6a0174b-0f9f-4b72-a404-439c25a15ec9"
        }, 
        "ansible_processor": [
            "0", 
            "GenuineIntel", 
            "Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz"
        ], 
        "ansible_processor_cores": 1, 
        "ansible_processor_count": 1, 
        "ansible_processor_threads_per_core": 1, 
        "ansible_processor_vcpus": 1, 
        "ansible_product_name": "VMware Virtual Platform", 
        "ansible_product_serial": "VMware-56 4d f7 ae 22 ca 1a 94-0f 51 de bd d1 01 a8 c7", 
        "ansible_product_uuid": "AEF74D56-CA22-941A-0F51-DEBDD101A8C7", 
        "ansible_product_version": "None", 
        "ansible_python": {
            "executable": "/usr/bin/python", 
            "has_sslcontext": true, 
            "type": "CPython", 
            "version": {
                "major": 2, 
                "micro": 5, 
                "minor": 7, 
                "releaselevel": "final", 
                "serial": 0
            }, 
            "version_info": [
                2, 
                7, 
                5, 
                "final", 
                0
            ]
        }, 
        "ansible_python_version": "2.7.5", 
        "ansible_real_group_id": 0, 
        "ansible_real_user_id": 0, 
        "ansible_selinux": {
            "status": "disabled"
        }, 
        "ansible_selinux_python_present": true, 
        "ansible_service_mgr": "systemd", 
        "ansible_ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHN5nr0MqsICjVJdjFRKBty6woRTynokXmAIMVv2KDJatAe4s+AcJbeXa/F6STBNg3lSv7E/tMuRqfhg1HNgQXo=", 
        "ansible_ssh_host_key_ed25519_public": "AAAAC3NzaC1lZDI1NTE5AAAAIOdVpn9SHhP8EuyhGSVsf7PhpbGXVMA/Y0JPc4J3yGrB", 
        "ansible_ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABAQCwSeY75Lwu9XO7LrCAa/KB+e+5x/Sm8JtC6C70JUai/PHvL1uMWOalZtiPrCsaoNsokBLvnMjA/fqrAjY0Q+hVVifJt0tM4TgN5akeKQkrZsZ7WdxKZS8mMyxpgJFWvaPmBg+gCTDRQdafJJdXTwHJ70Gt/Fas85EF/uV4SUUMMUb/xts20BIOu0CznS9qmrWU8yS0p4AogSsmuWtnqzlqSaiEdpe38Cz6vIuZymsc0t4JltKu04cg2+D9pSp/YWXF/yMq2uVXidOgWQeTDkxX6hPu/qTau49DiSB/eS8+RUeguI5ibrr1brbl5hGODgI5e/yfCnZ/VxWXhcoJEF1D", 
        "ansible_swapfree_mb": 774, 
        "ansible_swaptotal_mb": 774, 
        "ansible_system": "Linux", 
        "ansible_system_capabilities": [
            "cap_chown", 
            "cap_dac_override", 
            "cap_dac_read_search", 
            "cap_fowner", 
            "cap_fsetid", 
            "cap_kill", 
            "cap_setgid", 
            "cap_setuid", 
            "cap_setpcap", 
            "cap_linux_immutable", 
            "cap_net_bind_service", 
            "cap_net_broadcast", 
            "cap_net_admin", 
            "cap_net_raw", 
            "cap_ipc_lock", 
            "cap_ipc_owner", 
            "cap_sys_module", 
            "cap_sys_rawio", 
            "cap_sys_chroot", 
            "cap_sys_ptrace", 
            "cap_sys_pacct", 
            "cap_sys_admin", 
            "cap_sys_boot", 
            "cap_sys_nice", 
            "cap_sys_resource", 
            "cap_sys_time", 
            "cap_sys_tty_config", 
            "cap_mknod", 
            "cap_lease", 
            "cap_audit_write", 
            "cap_audit_control", 
            "cap_setfcap", 
            "cap_mac_override", 
            "cap_mac_admin", 
            "cap_syslog", 
            "35", 
            "36+ep"
        ], 
        "ansible_system_capabilities_enforced": "True", 
        "ansible_system_vendor": "VMware, Inc.", 
        "ansible_uptime_seconds": 5667, 
        "ansible_user_dir": "/root", 
        "ansible_user_gecos": "root", 
        "ansible_user_gid": 0, 
        "ansible_user_id": "root", 
        "ansible_user_shell": "/bin/bash", 
        "ansible_user_uid": 0, 
        "ansible_userspace_architecture": "x86_64", 
        "ansible_userspace_bits": "64", 
        "ansible_virtualization_role": "guest", 
        "ansible_virtualization_type": "VMware", 
        "discovered_interpreter_python": "/usr/bin/python", 
        "gather_subset": [
            "all"
        ], 
        "module_setup": true
    }, 
    "changed": false
}
很多信息

ansibe2.9 api调用 

简书挺详细的:https://www.jianshu.com/p/ec1e4d8438e9

官网  https://docs.ansible.com/ansible/latest/dev_guide/developing_api.html

查看版本信息

[root@mcw01 ~/mcw]$ ansible --version
ansible 2.9.27
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/mcw', u'/root/mcw']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Aug  4 2017, 00:39:18) [GCC 4.8.5 20150623 (Red Hat 4.8.5-16)]
[root@mcw01 ~/mcw]$ 

api调用程序示例

#!/usr/bin/env python

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import json
import shutil

import ansible.constants as C
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.module_utils.common.collections import ImmutableDict
from ansible.inventory.manager import InventoryManager
from ansible.parsing.dataloader import DataLoader
from ansible.playbook.play import Play
from ansible.plugins.callback import CallbackBase
from ansible.vars.manager import VariableManager
from ansible import context


# Create a callback plugin so we can capture the output
class ResultsCollectorJSONCallback(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 __init__(self, *args, **kwargs):
        super(ResultsCollectorJSONCallback, self).__init__(*args, **kwargs)
        self.host_ok = {}
        self.host_unreachable = {}
        self.host_failed = {}

    def v2_runner_on_unreachable(self, result):
        host = result._host
        self.host_unreachable[host.get_name()] = result

    def v2_runner_on_ok(self, result, *args, **kwargs):
        """Print a json representation of the result.

        Also, store the result in an instance attribute for retrieval later
        """
        host = result._host
        self.host_ok[host.get_name()] = result
        print(json.dumps({host.name: result._result}, indent=4))

    def v2_runner_on_failed(self, result, *args, **kwargs):
        host = result._host
        self.host_failed[host.get_name()] = result


def main():
    host_list = ['10.0.0.12']#['localhost', 'www.example.com', 'www.google.com']
    # since the API is constructed for CLI it expects certain options to always be set in the context object
    context.CLIARGS = ImmutableDict(connection='smart', module_path=['/to/mymodules', '/usr/share/ansible'], forks=10, become=None,
                                    become_method=None, become_user=None, check=False, diff=False)
    # required for
    # https://github.com/ansible/ansible/blob/devel/lib/ansible/inventory/manager.py#L204
    sources = ','.join(host_list)
    if len(host_list) == 1:
        sources += ','

    # initialize needed objects
    loader = DataLoader()  # Takes care of finding and reading yaml, json and ini files
    passwords = dict(vault_pass='secret')

    # Instantiate our ResultsCollectorJSONCallback for handling results as they come in. Ansible expects this to be one of its main display outlets
    results_callback = ResultsCollectorJSONCallback()

    # create inventory, use path to host config file as source or hosts in a comma separated string
    inventory = InventoryManager(loader=loader, sources=sources)

    # variable manager takes care of merging all the different sources to give you a unified view of variables available in each context
    variable_manager = VariableManager(loader=loader, inventory=inventory)

    # instantiate task queue manager, which takes care of forking and setting up all objects to iterate over host list and tasks
    # IMPORTANT: This also adds library dirs paths to the module loader
    # IMPORTANT: and so it must be initialized before calling `Play.load()`.
    tqm = TaskQueueManager(
        inventory=inventory,
        variable_manager=variable_manager,
        loader=loader,
        passwords=passwords,
        stdout_callback=results_callback,  # Use our custom callback instead of the ``default`` callback plugin, which prints to stdout
    )

    # create data structure that represents our play, including tasks, this is basically what our YAML loader does internally.
    play_source = dict(
        name="Ansible Play",
        hosts=host_list,
        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}}'))),
            dict(action=dict(module='command', args=dict(cmd='/usr/bin/uptime'))),
        ]
    )

    # Create play object, playbook objects use .load instead of init or new methods,
    # this will also automatically create the task objects from the info provided in play_source
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)

    # Actually run it
    try:
        result = tqm.run(play)  # most interesting data for a play is actually sent to the callback's methods
    finally:
        # we always need to cleanup child procs and the structures we use to communicate with them
        tqm.cleanup()
        if loader:
            loader.cleanup_all_tmp_files()

    # Remove ansible tmpdir
    shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)

    print("UP ***********")
    for host, result in results_callback.host_ok.items():
        print('{0} >>> {1}'.format(host, result._result['stdout']))

    print("FAILED *******")
    for host, result in results_callback.host_failed.items():
        print('{0} >>> {1}'.format(host, result._result['msg']))

    print("DOWN *********")
    for host, result in results_callback.host_unreachable.items():
        print('{0} >>> {1}'.format(host, result._result['msg']))


if __name__ == '__main__':
    main()

执行结果:

[root@mcw01 ~/mcw]$ python 2.9ansibleapi.py 
{
    "10.0.0.12": {
        "stderr_lines": [], 
        "changed": true, 
        "end": "2022-10-23 22:28:26.502922", 
        "_ansible_no_log": false, 
        "stdout": "10.0.0.11\n11.py\n2.9ansibleapi.py\nanaconda-ks.cfg\nAnsible\napache-tomcat-8.0.27\napache-tomcat-8.0.27.tar.gz\ncpis\ndemo.sh\ndump.rdb\njpress-web-newest\njpress-web-newest.tar.gz\njpress-web-newest.war\nlogs\nmcw\nmcw.py\nsite-packages.zip\nsonarqube\nsonar-scanner-cli-4.7.0.2747-linux.zip\ntomcat", 
        "cmd": "ls", 
        "start": "2022-10-23 22:28:26.491623", 
        "delta": "0:00:00.011299", 
        "stderr": "", 
        "rc": 0, 
        "invocation": {
            "module_args": {
                "warn": true, 
                "executable": null, 
                "_uses_shell": true, 
                "strip_empty_ends": true, 
                "_raw_params": "ls", 
                "removes": null, 
                "argv": null, 
                "creates": null, 
                "chdir": null, 
                "stdin_add_newline": true, 
                "stdin": null
            }
        }, 
        "stdout_lines": [
            "10.0.0.11", 
            "11.py", 
            "2.9ansibleapi.py", 
            "anaconda-ks.cfg", 
            "Ansible", 
            "apache-tomcat-8.0.27", 
            "apache-tomcat-8.0.27.tar.gz", 
            "cpis", 
            "demo.sh", 
            "dump.rdb", 
            "jpress-web-newest", 
            "jpress-web-newest.tar.gz", 
            "jpress-web-newest.war", 
            "logs", 
            "mcw", 
            "mcw.py", 
            "site-packages.zip", 
            "sonarqube", 
            "sonar-scanner-cli-4.7.0.2747-linux.zip", 
            "tomcat"
        ], 
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }
    }
}
{
    "10.0.0.12": {
        "msg": "10.0.0.11\n11.py\n2.9ansibleapi.py\nanaconda-ks.cfg\nAnsible\napache-tomcat-8.0.27\napache-tomcat-8.0.27.tar.gz\ncpis\ndemo.sh\ndump.rdb\njpress-web-newest\njpress-web-newest.tar.gz\njpress-web-newest.war\nlogs\nmcw\nmcw.py\nsite-packages.zip\nsonarqube\nsonar-scanner-cli-4.7.0.2747-linux.zip\ntomcat", 
        "changed": false, 
        "_ansible_verbose_always": true, 
        "_ansible_no_log": false
    }
}
{
    "10.0.0.12": {
        "stderr_lines": [], 
        "cmd": [
            "/usr/bin/uptime"
        ], 
        "end": "2022-10-23 22:28:27.178912", 
        "_ansible_no_log": false, 
        "stdout": " 22:28:27 up 1 day,  6:46,  2 users,  load average: 0.00, 0.01, 0.05", 
        "changed": true, 
        "rc": 0, 
        "start": "2022-10-23 22:28:27.165476", 
        "stderr": "", 
        "delta": "0:00:00.013436", 
        "invocation": {
            "module_args": {
                "creates": null, 
                "executable": null, 
                "_uses_shell": false, 
                "strip_empty_ends": true, 
                "_raw_params": "/usr/bin/uptime", 
                "removes": null, 
                "argv": null, 
                "warn": true, 
                "chdir": null, 
                "stdin_add_newline": true, 
                "stdin": null
            }
        }, 
        "stdout_lines": [
            " 22:28:27 up 1 day,  6:46,  2 users,  load average: 0.00, 0.01, 0.05"
        ]
    }
}
UP ***********
10.0.0.12 >>>  22:28:27 up 1 day,  6:46,  2 users,  load average: 0.00, 0.01, 0.05
FAILED *******
DOWN *********
[root@mcw01 ~/mcw]$ 

我们将上面的程序,任务列表里的两个注释掉,只保留一个  执行uptime的命令。执行脚本,应该是相当于执行ansible 10.0.0.12 -m command -a "/usr/bin/uptime"

    play_source = dict(
        name="Ansible Play",
        hosts=host_list,
        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}}'))),
            dict(action=dict(module='command', args=dict(cmd='/usr/bin/uptime'))),
        ]
    )

这相当于写剧本的方式。使用哪个模块,参数是什么。

看修改后的执行结果:有执行结果数据。

[root@mcw01 ~/mcw]$ python 2.9ansibleapi.py 
{
    "10.0.0.12": {
        "stderr_lines": [], 
        "cmd": [
            "/usr/bin/uptime"
        ], 
        "end": "2022-10-23 22:36:23.669234", 
        "_ansible_no_log": false, 
        "stdout": " 22:36:23 up 1 day,  6:54,  2 users,  load average: 0.13, 0.04, 0.05", 
        "changed": true, 
        "rc": 0, 
        "start": "2022-10-23 22:36:23.658986", 
        "stderr": "", 
        "delta": "0:00:00.010248", 
        "invocation": {
            "module_args": {
                "creates": null, 
                "executable": null, 
                "_uses_shell": false, 
                "strip_empty_ends": true, 
                "_raw_params": "/usr/bin/uptime", 
                "removes": null, 
                "argv": null, 
                "warn": true, 
                "chdir": null, 
                "stdin_add_newline": true, 
                "stdin": null
            }
        }, 
        "stdout_lines": [
            " 22:36:23 up 1 day,  6:54,  2 users,  load average: 0.13, 0.04, 0.05"
        ], 
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }
    }
}
UP ***********
10.0.0.12 >>>  22:36:23 up 1 day,  6:54,  2 users,  load average: 0.13, 0.04, 0.05
FAILED *******
DOWN *********
[root@mcw01 ~/mcw]$ 

最后的三个打印是任务执行ok或者失败或者主机不可达的结果打印。我们这里是正常执行命令获取到uptime数据。所以是ok那里打印出了数据。它是for循环后面的,然后获取到主机和主机执行命令的结果。

 api调用程序分析(类似于runner ip)

我们只需要定义好hosts主机,主机组。然后定义好任务就可以了。如果有需要,可以对执行返回结果做些操作。:

[root@mcw01 ~/mcw]$ cat 2.9ansibleapi.py 
#!/usr/bin/env python

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import json
import shutil

import ansible.constants as C
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.module_utils.common.collections import ImmutableDict
from ansible.inventory.manager import InventoryManager
from ansible.parsing.dataloader import DataLoader
from ansible.playbook.play import Play
from ansible.plugins.callback import CallbackBase
from ansible.vars.manager import VariableManager
from ansible import context


# Create a callback plugin so we can capture the output
class ResultsCollectorJSONCallback(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 __init__(self, *args, **kwargs):
        super(ResultsCollectorJSONCallback, self).__init__(*args, **kwargs)
        self.host_ok = {}
        self.host_unreachable = {}
        self.host_failed = {}

    def v2_runner_on_unreachable(self, result):
        host = result._host
        self.host_unreachable[host.get_name()] = result

    def v2_runner_on_ok(self, result, *args, **kwargs):
        """Print a json representation of the result.

        Also, store the result in an instance attribute for retrieval later
        """
        host = result._host
        self.host_ok[host.get_name()] = result
        print(json.dumps({host.name: result._result}, indent=4))  #这就是我们在执行程序之后看到的结果json.成功才有

    def v2_runner_on_failed(self, result, *args, **kwargs):
        host = result._host
        self.host_failed[host.get_name()] = result


def main():
    host_list = ['10.0.0.12']#定义主机['localhost', 'www.example.com', 'www.google.com']
    # since the API is constructed for CLI it expects certain options to always be set in the context object
    context.CLIARGS = ImmutableDict(connection='smart', module_path=['/to/mymodules', '/usr/share/ansible'], forks=10, become=None,
                                    become_method=None, become_user=None, check=False, diff=False)
    # required for
    # https://github.com/ansible/ansible/blob/devel/lib/ansible/inventory/manager.py#L204
    sources = ','.join(host_list)
    if len(host_list) == 1:
        sources += ','  #将主机以逗号分隔都拼接起来,如果只有一个数据,那么ip后面拼接个逗号
    print(sources) # 结果: 10.0.0.12,
    # initialize needed objects
    loader = DataLoader()  #打印结果<ansible.parsing.dataloader.DataLoader object at 0x1156fd0># Takes care of finding and reading yaml, json and ini files
    passwords = dict(vault_pass='secret') #打印结果:{'vault_pass': 'secret'}

    # Instantiate our ResultsCollectorJSONCallback for handling results as they come in. Ansible expects this to be one of its main display outlets
    results_callback = ResultsCollectorJSONCallback() #结果:回调函数对象

    # create inventory, use path to host config file as source or hosts in a comma separated string
    inventory = InventoryManager(loader=loader, sources=sources) #打印结果:inventory管理对象<ansible.inventory.manager.InventoryManager object at 0x1fe3550>
                                    #数据加载对象,10.0.0.12,
    # variable manager takes care of merging all the different sources to give you a unified view of variables available in each context
    variable_manager = VariableManager(loader=loader, inventory=inventory)  #变量管理对象<ansible.vars.manager.VariableManager object at 0x208d5d0>

    # instantiate task queue manager, which takes care of forking and setting up all objects to iterate over host list and tasks
    # IMPORTANT: This also adds library dirs paths to the module loader
    # IMPORTANT: and so it must be initialized before calling `Play.load()`.
    tqm = TaskQueueManager(    #打印结果:任务队列管理对象
        inventory=inventory,  #任务对象管理对象,传inventory管理对象,传变量管理对象,传数据加载对象,传密码,传回调函数对象
        variable_manager=variable_manager,  #上面跟我们相关的只有主机列表,其它不变就行啊。传递的参数都是刚刚定义好的
        loader=loader,
        passwords=passwords,
        stdout_callback=results_callback,  # Use our custom callback instead of the ``default`` callback plugin, which prints to stdout
    )

    # create data structure that represents our play, including tasks, this is basically what our YAML loader does internally.
    play_source = dict(   #剧本源,是个字典,指定剧本名称吗?指定主机列表,指定是否需要收集facts
        name="Ansible Play", #指定任务列表,任务列表中可以存放多个任务。
        hosts=host_list,    #这跟写剧本似的,剧本就是多个任务聚集起来的。每个任务有name,有使用哪个模块,使用了什么参数。
        gather_facts='no',  #这里也是这样。剧本里面还可以定义变量,循环,判断,注册变量等等,这些写法应该是不同的。如下,
        tasks=[            #将任务一ls的执行结果注册为变量,变量名是shell_out。第二个任务调用这个注册变量的变量名,然后点stdout得到注册变量shell执行的标准输出
           # dict(action=dict(module='shell', args='ls'), register='shell_out'),#这就是变量在任务之间的传递。可以参考写剧本,去找这个任务列表怎么实现对应功能的
           # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}'))),  #所以我们需要在任务列表中执行任务,在hosts中定义主机和主机组。有这两个基本上
            dict(action=dict(module='command', args=dict(cmd='/usr/bin/uptime'))),  #就能写剧本了,实现剧本功能了。我们主要关注这两点
        ]
    )

    # Create play object, playbook objects use .load instead of init or new methods,
    # this will also automatically create the task objects from the info provided in play_source
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)  #打印结果:Ansible Play,估计是用了str方法了。
        #实例化一个剧本对象,将剧本源(名字,主机,是否收集facts,有哪些剧本任务)导入到剧本对象;两变量管理对象导入到剧本对象中,将数据加载对象导入。估计内部会进行变量渲染等等之类的吧。暂时不需要关心
    # Actually run it
    try:  #运行剧本。将剧本传入到任务队列管理里面的run方法中。这里面应该是对剧本任务进行消费。剧本对象传到任务队列里面了。里面包含了剧本需要的主机,剧本有哪些任务,剧本使用的变量等。
        result = tqm.run(play)  # most interesting data for a play is actually sent to the callback's methods
    finally:        #result打印结果好像只是个0,难道是显示执行成功的意思?我们看到执行的结果字典,应该就是在result和play之间哪里打印的。如果没有意外应该是result这里,运行剧本任务
        # we always need to cleanup child procs and the structures we use to communicate with them  #然后将运行结果在终端上打印出来这个结果字典
        tqm.cleanup()  #清理临时文件,也就是执行任务的过程中,会创建临时文件。任务执行完成,对临时文件进行清理。我们写程序也可以这样做。
        if loader:
            loader.cleanup_all_tmp_files()

    # Remove ansible tmpdir  #C.DEFAULT_LOCAL_TMP是/root/.ansible/tmp/ansible-local-16916wo3RhL目录,里面有个临时文件101 /root/.ansible/tmp/ansible-tmp-1666015891.13-5454-129638497331557/AnsiballZ_command.py  。
    shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)  

    print("results_callback:  ",results_callback) #<__main__.ResultsCollectorJSONCallback object at 0x2858550>
    print("results_callback.host_ok",results_callback.host_ok) #{'10.0.0.12': <ansible.executor.task_result.TaskResult object at 0x203dd90>}
    print("results_callback.host_ok.items: ",results_callback.host_ok.items()) #[('10.0.0.12', <ansible.executor.task_result.TaskResult object at 0x203dd90>)]
    for host, result in results_callback.host_ok.items():
        print(host,result)  #10.0.0.12 <ansible.executor.task_result.TaskResult object at 0x203dd90>
        print("result._result: ",result._result)
        print("结果对象里找表准输出,就是剧本执行的输出信息,这里就是命令uptime的执行打印结果: ",result._result['stdout'])

        {'stderr_lines': [], u'cmd': [u'/usr/bin/uptime'], u'end': u'2022-10-24 00:31:38.590871', '_ansible_no_log': False, u'stdout': u' 00:31:38 up 1 day,  8:49,  2 users,  load average: 0.00, 0.01, 0.05', u'changed': True, u'rc': 0, u'start': u'2022-10-24 00:31:38.580309', u'stderr': u'', u'delta': u'0:00:00.010562', u'invocation': {u'module_args': {u'creates': None, u'executable': None, u'_uses_shell': False, u'strip_empty_ends': True, u'_raw_params': u'/usr/bin/uptime', u'removes': None, u'argv': None, u'warn': True, u'chdir': None, u'stdin_add_newline': True, u'stdin': None}}, 'stdout_lines': [u' 00:31:38 up 1 day,  8:49,  2 users,  load average: 0.00, 0.01, 0.05'], 'ansible_facts': {u'discovered_interpreter_python': u'/usr/bin/python'}}

    将数据整理如下:
                {'stderr_lines': [], 
             u'cmd': [u'/usr/bin/uptime'], 
             u'end': u'2022-10-24 00:31:38.590871', 
             '_ansible_no_log': False,
             u'stdout': u' 00:31:38 up 1 day,  8:49,  2 users,  load average: 0.00, 0.01, 0.05', 
             u'changed': True, 
             u'rc': 0,
             u'start': u'2022-10-24 00:31:38.580309',
             u'stderr': u'', 
             u'delta': u'0:00:00.010562', 
             u'invocation': {
                          u'module_args': {u'creates': None, 
                                           u'executable': None, 
                                           u'_uses_shell': False, 
                                           u'strip_empty_ends': True,
                                           u'_raw_params': u'/usr/bin/uptime',
                                           u'removes': None, 
                                           u'argv': None, 
                                           u'warn': True, 
                                           u'chdir': None,
                                          u'stdin_add_newline': True, 
                                           u'stdin': None
                            }
                    },
             'stdout_lines': [u' 00:31:38 up 1 day,  8:49,  2 users,  load average: 0.00, 0.01, 0.05'],
             'ansible_facts': {u'discovered_interpreter_python': u'/usr/bin/python'}}
        上面是result._result打印出来的。也就是我们需要指定的键,直接字典的方式取值就行了。标准输出就是命令的结果。回调函数,运行ok下面打印的也是这个
                
    
    
    print("UP ***********")
    for host, result in results_callback.host_ok.items():
        print('{0} >>> {1}'.format(host, result._result['stdout']))

    print("FAILED *******")
    for host, result in results_callback.host_failed.items():
    #当我们的任务里面dict(action=dict(module='command', args=dict(cmd='cat /usr/bin/uptimebbb'))),查看不存在的文件匹配到失败时。打印信息如下
        print('{0} >>> {1}'.format(host, result._result['msg'])) #10.0.0.12 >>> non-zero return code
        print("失败:",result._result)
                失败: {'stderr_lines': [u'cat: /usr/bin/uptimebbb: No such file or directory'], u'cmd': [u'cat', u'/usr/bin/uptimebbb'], u'stdout': u'', u'msg': u'non-zero return code', u'delta': u'0:00:00.011209', 'stdout_lines': [], 'ansible_facts': {u'discovered_interpreter_python': u'/usr/bin/python'}, u'end': u'2022-10-24 00:44:23.455248', '_ansible_no_log': False, u'changed': True, u'start': u'2022-10-24 00:44:23.444039', u'stderr': u'cat: /usr/bin/uptimebbb: No such file or directory', u'rc': 1, u'invocation': {u'module_args': {u'creates': None, u'executable': None, u'_uses_shell': False, u'strip_empty_ends': True, u'_raw_params': u'cat /usr/bin/uptimebbb', u'removes': None, u'argv': None, u'warn': True, u'chdir': None, u'stdin_add_newline': True, u'stdin': None}}}
                
                整理如下:我们这里定义打印的是msg.,
                        {'stderr_lines': [u'cat: /usr/bin/uptimebbb: No such file or directory'],
                         u'cmd': [u'cat', u'/usr/bin/uptimebbb'],
                         u'stdout': u'', 
                         u'msg': u'non-zero return code',
                         u'delta': u'0:00:00.011209', 
                         'stdout_lines': [],
                         'ansible_facts': {u'discovered_interpreter_python': u'/usr/bin/python'}, 
                         u'end': u'2022-10-24 00:44:23.455248',
                         '_ansible_no_log': False,
                         u'changed': True, 
                         u'start': u'2022-10-24 00:44:23.444039',
                         u'stderr': u'cat: /usr/bin/uptimebbb: No such file or directory',
                         u'rc': 1, 
                         u'invocation': {
                                   u'module_args': {u'creates': None,
                                                    u'executable': None, 
                                                    u'_uses_shell': False, 
                                                    u'strip_empty_ends': True,
                                                    u'_raw_params': u'cat /usr/bin/uptimebbb',
                                                    u'removes': None, 
                                                    u'argv': None, 
                                                    u'warn': True,
                                                    u'chdir': None, 
                                                    u'stdin_add_newline': True, 
                                                    u'stdin': None}}
                         
                         }

    print("DOWN *********")
    for host, result in results_callback.host_unreachable.items():
        print('{0} >>> {1}'.format(host, result._result['msg']))


if __name__ == '__main__':
    main()
[root@mcw01 ~/mcw]$ 

2.9传参的方式,执行命令,实现runner api。

[root@mcw01 ~/mcw]$ cat mytest.py 
# _*_ coding:utf-8 __*__
# !/usr/bin/env python

from __future__ import (absolute_import, division, print_function)

__metaclass__ = type

import json
import shutil

import ansible.constants as C
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.module_utils.common.collections import ImmutableDict
from ansible.inventory.manager import InventoryManager
from ansible.parsing.dataloader import DataLoader
from ansible.playbook.play import Play
from ansible.plugins.callback import CallbackBase
from ansible.vars.manager import VariableManager
from ansible import context


# Create a callback plugin so we can capture the output
class ResultsCollectorJSONCallback(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 __init__(self, *args, **kwargs):
        super(ResultsCollectorJSONCallback, self).__init__(*args, **kwargs)
        self.host_ok = {}
        self.host_unreachable = {}
        self.host_failed = {}

    def v2_runner_on_unreachable(self, result):
        host = result._host
        self.host_unreachable[host.get_name()] = result

    def v2_runner_on_ok(self, result, *args, **kwargs):
        """Print a json representation of the result.

        Also, store the result in an instance attribute for retrieval later
        """
        host = result._host
        self.host_ok[host.get_name()] = result
        print(json.dumps({host.name: result._result}, indent=4))

    def v2_runner_on_failed(self, result, *args, **kwargs):
        host = result._host
        self.host_failed[host.get_name()] = result


def main(host_list,module_name,module_args):
    host_list = host_list  # ['localhost', 'www.example.com', 'www.google.com']
    # since the API is constructed for CLI it expects certain options to always be set in the context object
    context.CLIARGS = ImmutableDict(connection='smart', module_path=['/to/mymodules', '/usr/share/ansible'], forks=10,
                                    become=None,
                                    become_method=None, become_user=None, check=False, diff=False)
    # required for
    # https://github.com/ansible/ansible/blob/devel/lib/ansible/inventory/manager.py#L204
    sources = ','.join(host_list)
    if len(host_list) == 1:
        sources += ','
    # initialize needed objects
    loader = DataLoader()  # Takes care of finding and reading yaml, json and ini files
    passwords = dict(vault_pass='secret')
    # Instantiate our ResultsCollectorJSONCallback for handling results as they come in. Ansible expects this to be one of its main display outlets
    results_callback = ResultsCollectorJSONCallback()

    # create inventory, use path to host config file as source or hosts in a comma separated string
    inventory = InventoryManager(loader=loader, sources=sources)

    # variable manager takes care of merging all the different sources to give you a unified view of variables available in each context
    variable_manager = VariableManager(loader=loader, inventory=inventory)

    # instantiate task queue manager, which takes care of forking and setting up all objects to iterate over host list and tasks
    # IMPORTANT: This also adds library dirs paths to the module loader
    # IMPORTANT: and so it must be initialized before calling `Play.load()`.
    tqm = TaskQueueManager(
        inventory=inventory,
        variable_manager=variable_manager,
        loader=loader,
        passwords=passwords,
        stdout_callback=results_callback,
        # Use our custom callback instead of the ``default`` callback plugin, which prints to stdout
    )

    # create data structure that represents our play, including tasks, this is basically what our YAML loader does internally.
    play_source = dict(
        name="Ansible Play",
        hosts=host_list,
        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}}'))),
            # dict(action=dict(module='command', args=dict(cmd='cat /usr/bin/uptimebbb'))),
            dict(action=dict(module=module_name, args=module_args)),
        ]
    )

    # Create play object, playbook objects use .load instead of init or new methods,
    # this will also automatically create the task objects from the info provided in play_source
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
    # Actually run it
    try:
        result = tqm.run(play)  # most interesting data for a play is actually sent to the callback's methods
    finally:
        # we always need to cleanup child procs and the structures we use to communicate with them
        tqm.cleanup()
        if loader:
            loader.cleanup_all_tmp_files()

    # Remove ansible tmpdir
    shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)

    print("UP ***********")
    for host, result in results_callback.host_ok.items():
        print('{0} >>> {1}'.format(host, result._result['stdout']))

    print("FAILED *******")
    for host, result in results_callback.host_failed.items():
        print('{0} >>> {1}'.format(host, result._result['msg']))
        print("失败:", result._result)
    print("DOWN *********")
    for host, result in results_callback.host_unreachable.items():
        print('{0} >>> {1}'.format(host, result._result['msg']))
        print("不可达:", result._result)


if __name__ == '__main__':
    option_dict={"become":True,"remote_user":"root"}
    module_name = 'shell'
    module_args = "/usr/bin/uptime"
    host_list = ['10.0.0.11','10.0.0.12']
    main(host_list,module_name,module_args)

[root@mcw01 ~/mcw]$ 

执行结果:

[root@mcw01 ~/mcw]$ python mytest.py 
{
    "10.0.0.12": {
        "stderr_lines": [], 
        "cmd": "/usr/bin/uptime", 
        "end": "2022-10-24 01:28:10.831660", 
        "_ansible_no_log": false, 
        "stdout": " 01:28:10 up 1 day,  9:46,  2 users,  load average: 0.00, 0.01, 0.05", 
        "changed": true, 
        "rc": 0, 
        "start": "2022-10-24 01:28:10.820105", 
        "stderr": "", 
        "delta": "0:00:00.011555", 
        "invocation": {
            "module_args": {
                "creates": null, 
                "executable": null, 
                "_uses_shell": true, 
                "strip_empty_ends": true, 
                "_raw_params": "/usr/bin/uptime", 
                "removes": null, 
                "argv": null, 
                "warn": true, 
                "chdir": null, 
                "stdin_add_newline": true, 
                "stdin": null
            }
        }, 
        "stdout_lines": [
            " 01:28:10 up 1 day,  9:46,  2 users,  load average: 0.00, 0.01, 0.05"
        ], 
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }
    }
}
{
    "10.0.0.11": {
        "stderr_lines": [], 
        "cmd": "/usr/bin/uptime", 
        "end": "2022-10-24 01:28:11.153952", 
        "_ansible_no_log": false, 
        "stdout": " 01:28:11 up 1 day,  9:46,  4 users,  load average: 0.68, 0.31, 0.24", 
        "changed": true, 
        "rc": 0, 
        "start": "2022-10-24 01:28:11.093208", 
        "stderr": "", 
        "delta": "0:00:00.060744", 
        "invocation": {
            "module_args": {
                "creates": null, 
                "executable": null, 
                "_uses_shell": true, 
                "strip_empty_ends": true, 
                "_raw_params": "/usr/bin/uptime", 
                "removes": null, 
                "argv": null, 
                "warn": true, 
                "chdir": null, 
                "stdin_add_newline": true, 
                "stdin": null
            }
        }, 
        "stdout_lines": [
            " 01:28:11 up 1 day,  9:46,  4 users,  load average: 0.68, 0.31, 0.24"
        ], 
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }
    }
}
UP ***********
10.0.0.11 >>>  01:28:11 up 1 day,  9:46,  4 users,  load average: 0.68, 0.31, 0.24
10.0.0.12 >>>  01:28:10 up 1 day,  9:46,  2 users,  load average: 0.00, 0.01, 0.05
FAILED *******
DOWN *********
[root@mcw01 ~/mcw]$ 

 打印的东西就是我们程序能实实现的一个功能

 ansible 1.9.6 api调用

runner api 简单调用案例,以及Runner类的初始化参数大全

程序:

import  ansible.runner
runner=ansible.runner.Runner(module_name='shell',module_args='hostname',pattern='all',forks=10)
result=runner.run()
for host,ret in result['contacted'].items():
    print(host,ret['stdout'])

只需要将模块名字,你用的参数,以及主机和主机组传进来就可以了。因为ad-hoc模式有这三个就可以使用了。想要更多信息那就看它的其它参数

执行结果

 

我将源码Runner类的参数放到下面,供参数设置使用

class Runner(object):
    ''' core API interface to ansible '''

    # see bin/ansible for how this is used...

    def __init__(self,
        host_list=C.DEFAULT_HOST_LIST,      # ex: /etc/ansible/hosts, legacy usage
        module_path=None,                   # ex: /usr/share/ansible
        module_name=C.DEFAULT_MODULE_NAME,  # ex: copy
        module_args=C.DEFAULT_MODULE_ARGS,  # ex: "src=/tmp/a dest=/tmp/b"
        forks=C.DEFAULT_FORKS,              # parallelism level
        timeout=C.DEFAULT_TIMEOUT,          # SSH timeout
        pattern=C.DEFAULT_PATTERN,          # which hosts?  ex: 'all', 'acme.example.org'
        remote_user=C.DEFAULT_REMOTE_USER,  # ex: 'username'
        remote_pass=C.DEFAULT_REMOTE_PASS,  # ex: 'password123' or None if using key
        remote_port=None,                   # if SSH on different ports
        private_key_file=C.DEFAULT_PRIVATE_KEY_FILE, # if not using keys/passwords
        background=0,                       # async poll every X seconds, else 0 for non-async
        basedir=None,                       # directory of playbook, if applicable
        setup_cache=None,                   # used to share fact data w/ other tasks
        vars_cache=None,                    # used to store variables about hosts
        transport=C.DEFAULT_TRANSPORT,      # 'ssh', 'paramiko', 'local'
        conditional='True',                 # run only if this fact expression evals to true
        callbacks=None,                     # used for output
        module_vars=None,                   # a playbooks internals thing
        play_vars=None,                     #
        play_file_vars=None,                #
        role_vars=None,                     #
        role_params=None,                   #
        default_vars=None,                  #
        extra_vars=None,                    # extra vars specified with he playbook(s)
        is_playbook=False,                  # running from playbook or not?
        inventory=None,                     # reference to Inventory object
        subset=None,                        # subset pattern
        check=False,                        # don't make any changes, just try to probe for potential changes
        diff=False,                         # whether to show diffs for template files that change
        environment=None,                   # environment variables (as dict) to use inside the command
        complex_args=None,                  # structured data in addition to module_args, must be a dict
        error_on_undefined_vars=C.DEFAULT_UNDEFINED_VAR_BEHAVIOR, # ex. False
        accelerate=False,                   # use accelerated connection
        accelerate_ipv6=False,              # accelerated connection w/ IPv6
        accelerate_port=None,               # port to use with accelerated connection
        vault_pass=None,
        run_hosts=None,                     # an optional list of pre-calculated hosts to run on
        no_log=False,                       # option to enable/disable logging for a given task
        run_once=False,                     # option to enable/disable host bypass loop for a given task
        become=False,                         # whether to run privelege escalation or not
        become_method=C.DEFAULT_BECOME_METHOD,
        become_user=C.DEFAULT_BECOME_USER,      # ex: 'root'
        become_pass=C.DEFAULT_BECOME_PASS,      # ex: 'password123' or None
        become_exe=C.DEFAULT_BECOME_EXE,        # ex: /usr/local/bin/sudo
        ):

        # used to lock multiprocess inputs and outputs at various levels
        self.output_lockfile  = OUTPUT_LOCKFILE
        self.process_lockfile = PROCESS_LOCKFILE

        if not complex_args:
            complex_args = {}

        # storage & defaults
        self.check            = check
        self.diff             = diff
        self.setup_cache      = utils.default(setup_cache, lambda: ansible.cache.FactCache())
        self.vars_cache       = utils.default(vars_cache, lambda: collections.defaultdict(dict))
        self.basedir          = utils.default(basedir, lambda: os.getcwd())
        self.callbacks        = utils.default(callbacks, lambda: DefaultRunnerCallbacks())
        self.generated_jid    = str(random.randint(0, 999999999999))
        self.transport        = transport
        self.inventory        = utils.default(inventory, lambda: ansible.inventory.Inventory(host_list))

        self.module_vars      = utils.default(module_vars, lambda: {})
        self.play_vars        = utils.default(play_vars, lambda: {})
        self.play_file_vars   = utils.default(play_file_vars, lambda: {})
        self.role_vars        = utils.default(role_vars, lambda: {})
        self.role_params      = utils.default(role_params, lambda: {})
        self.default_vars     = utils.default(default_vars, lambda: {})
        self.extra_vars       = utils.default(extra_vars, lambda: {})

        self.always_run       = None
        self.connector        = connection.Connector(self)
        self.conditional      = conditional
        self.delegate_to      = None
        self.module_name      = module_name
        self.forks            = int(forks)
        self.pattern          = pattern
        self.module_args      = module_args
        self.timeout          = timeout
        self.remote_user      = remote_user
        self.remote_pass      = remote_pass
        self.remote_port      = remote_port
        self.private_key_file = private_key_file
        self.background       = background
        self.become           = become
        self.become_method    = become_method
        self.become_user_var  = become_user
        self.become_user      = None
        self.become_pass      = become_pass
        self.become_exe       = become_exe
        self.is_playbook      = is_playbook
        self.environment      = environment
        self.complex_args     = complex_args
        self.error_on_undefined_vars = error_on_undefined_vars
        self.accelerate       = accelerate
        self.accelerate_port  = accelerate_port
        self.accelerate_ipv6  = accelerate_ipv6
        self.callbacks.runner = self
        self.omit_token       = '__omit_place_holder__%s' % sha1(os.urandom(64)).hexdigest()
        self.vault_pass       = vault_pass
        self.no_log           = no_log
        self.run_once         = run_once

我们直接打印结果json数据。刚刚是取了标准输出了。

 

 result是如下字典。多个主机的执行情况

{'dark': {}, 'contacted': {
    '10.0.0.11': {u'changed': True, u'end': u'2022-10-24 07:19:40.639601', u'stdout': u'mcw01', u'cmd': u'hostname',
                  u'start': u'2022-10-24 07:19:40.625335', u'delta': u'0:00:00.014266', u'stderr': u'', u'rc': 0,
                  'invocation': {'module_name': 'shell', 'module_complex_args': {}, 'module_args': u'hostname'},
                  u'warnings': []},
    '10.0.0.13': {u'changed': True, u'end': u'2022-10-24 13:58:03.096806', u'stdout': u'mcw03', u'cmd': u'hostname',
                  u'start': u'2022-10-24 13:58:03.087297', u'delta': u'0:00:00.009509', u'stderr': u'', u'rc': 0,
                  'invocation': {'module_name': 'shell', 'module_complex_args': {}, 'module_args': u'hostname'},
                  u'warnings': []},
    '10.0.0.12': {u'changed': True, u'end': u'2022-10-24 13:58:03.530927', u'stdout': u'mcw02', u'cmd': u'hostname',
                  u'start': u'2022-10-24 13:58:03.504361', u'delta': u'0:00:00.026566', u'stderr': u'', u'rc': 0,
                  'invocation': {'module_name': 'shell', 'module_complex_args': {}, 'module_args': u'hostname'},
                  u'warnings': []}}}

ret单个主机的信息如下:

{'10.0.0.11':
     {u'changed': True,
      u'end': u'2022-10-24 07:19:40.639601',
      u'stdout': u'mcw01',
      u'cmd': u'hostname',
      u'start': u'2022-10-24 07:19:40.625335',
      u'delta': u'0:00:00.014266',
      u'stderr': u'',
      u'rc': 0,
     'invocation': {
               'module_name': 'shell',
               'module_complex_args': {},
               'module_args': u'hostname'
              },
      u'warnings': []
      }

 }

按理说错误信息放到dark里面了。但是我这里收不到错误信息。

runner api 不只是打印成功的,还打印执行失败的错误信息

import sys
sys.path.append("/root/untitled6/Lib/site-packages")
import  ansible.runner
runner=ansible.runner.Runner(module_name='shell',host_list="/root/hosts",module_args='hostname',pattern='all',forks=10)
result=runner.run()
print(result)
print("##############################")
for host,ret in result['contacted'].items():
    print(host,ret['stdout'])
for host,ret in result['dark'].items():
    print(host,ret['msg'])

 

 

playbook api 

[root@mcw02 ~/ansible]$ cat key.yaml 
- hosts: "{{ hosts }}"
  gather_facts: false
  tasks:
    - name: key
      authorized_key: user=root key="{{ lookup('file','/root/.ssh/id_rsa.pub') }}"
[root@mcw02 ~/ansible]$ cat playapi.py   #api.
from ansible.inventory import  Inventory
from ansible.playbook import PlayBook
from ansible import callbacks
inventory=Inventory('./hosts')
stats=callbacks.AggregateStats()
playbook_cb=callbacks.PlaybookCallbacks()
runner_cb=callbacks.PlaybookRunnerCallbacks(stats)
results=PlayBook(playbook='key.yaml',callbacks=playbook_cb,runner_callbacks=runner_cb,stats=stats,inventory=inventory,extra_vars={'hosts':'all'})
res=results.run()
print(res)
[root@mcw02 ~/ansible]$ 

如下,确实调用了剧本key。yaml。我们传递的变量给模板,是所有主机,也是生效的。打印结果是json数据。我们指定了inventory文件。剧本实现了公钥分发到其它主机,将本机公钥写入了其它主机.ssh/authorized_keys中

 返回的结果有点简单

{'10.0.0.11': {'unreachable': 0, 'skipped': 0, 'ok': 1, 'changed': 1, 'failures': 0},
 '10.0.0.13': {'unreachable': 0, 'skipped': 0, 'ok': 1, 'changed': 1, 'failures': 0},
 '10.0.0.12': {'unreachable': 1, 'skipped': 0, 'ok': 0, 'changed': 0, 'failures': 0}}

 使用flask封装我们的api,提供http远程执行ansible命令

效果

我们的程序运行在主机2上

 

 

 我们在主机3上执行curl命令访问接口,让主机2上的程序查主机3上的文件,成功返回执行结果,与主机3上的文件一致

 

 

 我们在浏览器上访问接口,成功返回数据

 此时,主机2是我们flask程序所在主机,也是ansible的主控机。我们可以通过http形式,在主机2上执行ad-hoc命令,使用各种模块。这就是使用flask封装了ansible的runner

 api效果。下面我们看其他的。我们已经知道主机3中有mcw.py,那么我们看一下文件内容。我们可以看到跟主机上是一样的。由此我们就能通过写前端页面,进行各种post和get请求,是对ansible api的请求,那么我们在网页上可以实现管理一群机器了。也可以用ansible写控制台

 我们根据调用剧本api,传的是剧本名称。后端会根据路径拼接成yaml文件。然后调用剧本api执行剧本。如果没有写路径,默认会从项目根路径找文件,如下。如果写了路径,就会找该路径下的文件

 

 

程序

下面就是flask蓝图

#_*_ coding:utf-8 __*__
from flask import Blueprint,request, render_template, redirect,abort
from apps.user.models import User
from ext import db

import json
import ansible.runner
from ansible.inventory import Inventory
from ansible.playbook import PlayBook
from ansible import callbacks

ansibleAPI_bp=Blueprint('ansibleAPI',__name__)

@ansibleAPI_bp.route('/',methods=['GET','POST'])
def index():
    return 'ok'

hostfile='/root/ansible/hosts'
@ansibleAPI_bp.route('/API/Ansible/playbook',methods=['GET','POST'])
def Playbook():
    """
    http://127.0.0.1:5000/API/Asible/playbook?ip=2.2.2.2&playbook=test
    :return:
    """
    print(request.args.get('playbook'))
    vars={}
    inventory = Inventory(hostfile)
    stats = callbacks.AggregateStats()
    playbook_cb = callbacks.PlaybookCallbacks()
    runner_cb = callbacks.PlaybookRunnerCallbacks(stats)
    hosts=request.args.get('ip')
    task=request.args.get('playbook')
    vars['hosts']=hosts
    play=task+'.yaml'
    results = PlayBook(playbook=play, callbacks=playbook_cb, runner_callbacks=runner_cb, stats=stats,
                       inventory=inventory, extra_vars=vars   )
    res = results.run()
    return json.dumps(res,indent=4)
@ansibleAPI_bp.route('/API/Ansible/runner',methods=['GET','POST'])
def Runner():
    """
    curl -H "Conten-Type: application/json" -X POST -d '{"ip":"1.1.1.1","module":"shell","args":"ls -l"}' http://127.0.0.1:5000/API/Ansible/runner
    :return:
    """
    print(request.args)
    hosts=request.args.get('ip',None)
    module=request.args.get('module',None)
    args=request.args.get('args',None)
    if hosts is None or module is None or args is None:
        abort(400)
    runner = ansible.runner.Runner(module_name=module, module_args=args, pattern=hosts, forks=10,host_list=hostfile)
    tasks= runner.run()
    cpis={}
    cpis1={}
    for (hostname, result) in tasks['contacted'].items():
        if not 'failed' in result:
            cpis[hostname]=result['stdout']
    for (hostname, result) in tasks['dark'].items():
        cpis1[hostname]=result['msg']
    return render_template('ansibleApi/cpis.html',cpis=cpis,cpis1=cpis1)

 下面是前端程序cpis.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>魔降风云变</title>
</head>
<body>

<h1>################成功设备列表#######################</h1>
{% for k,v in cpis.items() %}
===========主机{{ k }}执行返回结果:================<br>
    {{ v }}<br>
{% endfor %}

<h1>##################失败设备列表#####################</h1>
{% for a,b in cpis1.items() %}
===========主机{{ a }}执行返回结果================<br>
    {{ b }}<br>
{% endfor %}
</body>
</html>

 

ansible 1.9 api 复制即用,不影响系统原有环境

需要用到sys.path.append(“..“),可以了解这里:https://blog.csdn.net/universe_R/article/details/123370672

遇到的问题,当我们appen加入到sys.path中后,依然找不到模块:

此时我打印sys.path查看到默认的搜索路径,根据默认的包搜索路径过滤找到了其他人安装的ansibe 2.9的包。也就是没有找到包,因为这个包的搜索顺序在前,那么我们将我们的1.9的包路径insert到列表中第一个元素前。

经过测试,当我们执行程序时,打印出的sys.path会添加程序执行当前目录,然后添加上我们insert或者append进去的路径,我们让自己的程序sleep多运行一会 ;在另外一处,我们隔两秒打印一次sys.path,发现并没有正在运行的程序添加的路径。也就是说,执行python程序,有公共的包搜索路径,如果你执行的程序加入了其它的包搜索路径是不会影响公共的python路径的,我们程序加进去的包路是临时加进去,只对当前执行的程序生效,对其它程序是没有影响的。也就是说,我们使用sys.path.append 或者是insert是安全的,不会因为当前程序的搜索包路径的优先级对其它可能存在的python程序产生影响,因为加进去的路径只对当前程序生效

import sys
sys.path.append("/root/untitled6/Lib/site-packages")
import  ansible.runner
runner=ansible.runner.Runner(module_name='shell',host_list="/root/hosts",module_args='hostname',pattern='all',forks=10)
result=runner.run()
print(result)
print("##############################")
for host,ret in result['contacted'].items():
    print(host,ret['stdout'])
for host,ret in result['dark'].items():
    print(host,ret['msg'])
View Code

首先我们看一下pycharm中环境。untitled6是windows上pycharm创建的一个项目,带有虚拟环境的。在pycharm中安装ansibe包失败,但是ansible依赖包已经装上了。在centos7虚拟机上源码包安装了ansibe 1.9,我们从python2.7的包目录下把ansibe包拷贝到笔记本的untitled6的虚拟环境包目录下了。也就是有了如下的ansibe包

 

 

 接下来我们看我们下面需要操作的Linux服务器。我们新装了三个虚拟机。目前是没有ansible的。我是提前将主机1的公钥分发到主机2和3上了,然后免密第一次登录上2和3.不太确定是否需要设置好免密。我们接下来想要将上面的项目拷贝到Linux服务器中使用。

 

 

将项目解压下来

 

 

 由于项目的虚拟环境python解释器是windows版本的,所以我们只能用一下Linux上原本的python解释器。后面可以考虑,虚拟环境中如何替换成Linux版python解释器,解除对别处资源的依赖性。

这里用Linux自身的装的python2.7执行我们写的一个简单程序,去调用ansibe api,发现无法导入模块。既然它找不到,那么我们就在执行这个文件之前指定它还能去哪里找包

 

 将项目的包目录追加到Linux安装的python2.7找包的列表中去。让这个解释器能找到我们项目的包。结果是找到的,但是没有inventory文件,那么我们就创建一个

 

 查看源码我们发现,这个参数应该是inventory文件,下面其实还有一个参数,但是注释是对象。而我们需要传的是文件。

 

 如下,我们成功获取到各个主机的信息。由于我们主机1没有对连接自身做免密,所以这里就不能访问执行。由此可知,这点和ansible软件还是一样的,都需要免密。而这里我们没有在Linux上安装ansible,用的只是可以使用的python解释器,这个解释器指定路径的方式让它能找到我们项目虚拟环境中的ansibe包路径、,如果便可以使用ansibe api去执行ansibe命令了。所以即使原系统环境中有yum安装的ansibe,不管是啥版本,和我们调用ansibe api是没有关系 的,。

 ansible其他一些使用总结

命令执行结果按原样换行

执行命令获得的结果,不是单行字符串显示,而是让它像终端执行命令一样多行展示

api 调用,获取命令执行结果的指定行和列数据。比如通过vmstat获取cpu使用率

shell命令取好值

 

 根据命令获取到指定数据,然后处理数据,100减去cpu空闲的再除以100,获得cpu使用率。

 api 第二种方式获取CPU使用率(shell输出指定行和指定列获取)

# _*_ coding:utf-8 _*_
import sys
sys.path.append("/root/untitled6/Lib/site-packages")
import  ansible.runner
runner=ansible.runner.Runner(module_name='shell',host_list="/root/hosts",module_args="vmstat",pattern='all',forks=10)
result=runner.run()
for host,ret in result['contacted'].items():
    print '=================================',host
    res=ret['stdout'].split('\n')
    print res
    print '#################'
    for i in res:
        for j in i.split():
           print j, 
        print
    shiyonglv=(100-int(res[-1].split()[-3]))/100
    print "CPU使用率为: ",shiyonglv,'%'
        
for host,ret in result['dark'].items():
    print host
    print ret['msg']

 

 

 api将返回数据按行和列封装到对象或者字典中

如果我们需要多个返回的数据。我们可以将数据分别保存到对象中或者时字典中,分别需要定义类和字典

 

posted @ 2021-12-14 03:35  马昌伟  阅读(2273)  评论(0编辑  收藏  举报
博主链接地址:https://www.cnblogs.com/machangwei-8/