返回总目录页

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 @   马昌伟  阅读(2546)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
博主链接地址:https://www.cnblogs.com/machangwei-8/
点击右上角即可分享
微信分享提示

目录导航