自动化运维:Ansible api 2.7封装

一、前提介绍

现在提倡自动化运维了,公司管理的机器也比较多,打算写一个自动化接口用,发现ansible这个工具还不错,查资料发现,ansible api2.0以前的版本使用起来算还比较方便、容易,但是api 2.0+,发现官方的代码,变得复杂很多,没办法,还是想搞一个接口用,于是,自己动手封装一个吧,现在最新的ansible api是2.7版本,封装也打算采用这个版本。来吧,开始吧!

二、参考资料

官方网站:https://docs.ansible.com/ansible/latest/dev_guide/developing_api.html
ansible api 2.0以前的api调用方式:
https://ansible-tran.readthedocs.io/en/latest/docs/developing_api.html?highlight=api
其他网站的参考,作者总结的很好:
http://www.mindg.cn/?p=2004
源码:https://github.com/ansible/ansible/tree/devel/lib/ansible

三、自己的封装

#!/usr/bin/env python
# 1、python3.6和ansible2.7.8 api环境
# 2、封装ansible2.7.8 api
# by CCUlin

import os
import json
import shutil
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.playbook_executor import PlaybookExecutor
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase
import ansible.constants as C


class ResultCallback(CallbackBase):
    """
    重构输出
    """
    def __init__(self, *args, **kwargs):
        super(ResultCallback, self).__init__(*args, **kwargs)
        self.host_ok = {}
        self.host_unreachable = {}
        self.host_failed = {}

    def v2_runner_on_ok(self, result, **kwargs):
    	"""成功"""
        self.host_ok[result._host.name] = result._result["stdout"]

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

    def v2_runner_on_failed(self, result, ignore_errors=False, **kwargs):
        """失败"""
        self.host_failed[result._host.name] = result._result["stderr"]


def runner(ansible_host_path, module, args):
    """
    类似Ad-Hoc命令
    :param ansible_host_path: 一个清单文件,一行一个ip就行
    :param module:
    :param args:
    :return:
    """
    Options = namedtuple('Options',
                         ['connection',
                          'module_path',
                          'forks',
                          'private_key_file',
                          'remote_user',
                          'become',
                          'become_method',
                          'become_user',
                          'check',
                          'diff'])
    options = Options(connection='smart',
                      module_path=None,
                      forks=10,
                      private_key_file="/home/admin/.ssh/id_rsa", # 你的私钥
                      remote_user="admin",      # 远程用户
                      become=True,
                      become_method="sudo",
                      become_user="root",
                      check=False,
                      diff=False)
    # 主要加载设置的变量
    loader = DataLoader()
    # 一个密码参数,可以设置为None,默认即可,没什么影响,我用的是秘钥登录
    passwords = dict(vault_pass='secret')
    # 结果回调
    callback = ResultCallback()
    # 设置传入的机器清单
    inventory = InventoryManager(loader=loader, sources=[ansible_host_path])
    # 加载之前的变量
    variable_manager = VariableManager(loader=loader, inventory=inventory)
    play_source = dict(
            name="Ansible Play",
            hosts="all",           # all表示匹配清单所有机器,看源码发现的
            gather_facts="no",
            tasks=[
                dict(action=dict(module=module, args=args), register='shell_out'),
             ]
        )
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)

    tqm = None
    try:
        tqm = TaskQueueManager(
                  inventory=inventory,
                  variable_manager=variable_manager,
                  loader=loader,
                  options=options,
                  passwords=passwords,
                  stdout_callback=callback,
              )
        result = tqm.run(play)
    finally:
        if tqm is not None:
            tqm.cleanup()
        shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
    # 重构输出
    result_raw = {'success': {}, 'failed': {}, 'unreachable': {}}
    for host, result in callback.host_ok.items():
        result_raw["success"][host] = result
    for host, result in callback.host_unreachable.items():
        result_raw['failed'][host] = result
    for host, result in callback.host_failed.items():
        result_raw['unreachable'][host] = result
    return json.dumps(result_raw, indent=4)
        

def runner_playbook(playbook_path, ansible_host_path):
    """
    运行playbook
    :param playbook_path: playbook的路径
    :param ansible_host_path:
    :return:
    """
    Options = namedtuple('Options',
                         ['connection',
                          'module_path',
                          'forks',
                          'private_key_file',
                          "become",
                          "become_method",
                          "become_user",
                          'check',
                          'diff',
                          "listhosts",
                          "listtasks",
                          "listtags",
                          "syntax"])
    options = Options(connection='smart',
                      module_path=None,
                      forks=10,
                      private_key_file="/home/admin/.ssh/id_rsa",  # 你的私钥
                      become=True,
                      become_method="sudo",
                      become_user="root",
                      check=False,
                      diff=False,
                      listhosts=None,
                      listtasks=None,
                      listtags=None,
                      syntax=None)

    loader = DataLoader()
    passwords = dict(vault_pass='secret')
    inventory = InventoryManager(loader=loader, sources=[ansible_host_path])
    variable_manager = VariableManager(loader=loader, inventory=inventory)

    pbex = PlaybookExecutor(playbooks=[playbook_path],
                            inventory=inventory,
                            variable_manager=variable_manager,
                            loader=loader,
                            options=options,
                            passwords=passwords)
    results = pbex.run()
    print(results)


if __name__ == "__main__":
    ansible_host_path = os.path.join(os.getcwd(), "hosts")
    data = runner(ansible_host_path, "shell", "whoami")
    print(data)
    # playbook_path = os.path.join(os.getcwd(), "site.yml")
    # runner_playbook(playbook_path, ansible_host_path)

四、总结

写接口之前,感觉很难,没什么可以参考的,但是,当你尝试找解决方法的时候,就会发现,你离成功越来越近。封装的时候,先去看了官方的例子,自己试验了一波,主要难点在在于传入的机器清单,这个看了官方的源码,看看人家怎么传参的,还有就是参考网上其他博主的文章,整个贯穿一遍之后,写这个ansible api的封装就不会很难了。运维之路任重而道远,所以还需继续努力!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值