21

从零打造企业内部Ansible自动化管理平台-第一章(Api)-渲染不变的昨天

 4 years ago
source link: https://blog.51cto.com/breaklinux/2485043
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

从零打造企业内部Ansible自动化管理平台-第一章(Api)

                                                                从零打造企业内部Ansible自动化管理平台-第一章

一. 背景;

      随着中下企业技术的快速技术迭代,以及微服务分布式架构的普及,传统运维系统运维环境治理方面,系统初始化,环境部署,环境一致性困难较大. 由此      ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,

      实现了批量系统配置、批量程序部署、环境快速部署迭代,批量运行命令等功能。

       Ansible 工作原理和关联模块介绍:

        ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括:

        (1)、连接插件connection plugins:负责和被监控端实现通信;

        (2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;

        (3)、各种模块核心模块、command模块、自定义模块;

        (4)、借助于插件完成记录日志邮件等功能;

        (5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。

二. 本章概述:

       本文主要描述ansible 2.7.2 版本官方python 3 版本Api 封装, (内容:Ansible 数据结构返回,host inventory动态主机,playbook 执行返回)

 三. 原生ansible-api 封装代码部分;

  官网参考连接: https://docs.ansible.com/ansible/latest/dev_guide/developing_api.html

  完整项目代码请移步到githup:  https://github.com/breaklinux/devops-bmc-api/

四.项目内部设计如下图:

     

devops-bmc-api.jpg

五.项目示例代码如下:

1.封装Ansible-api 实际代码片段如下: 

"""    
@author:lijx    
@contact: [email protected]    
@site: https://blog.51cto.com/breaklinux    
@version: 1.0 
@githup:https://github.com/breaklinux/devops-bmc-api/   
""" 
import json
from collections import namedtuple
from ansible.executor.task_queue_manager import TaskQueueManager
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.errors import AnsibleParserError

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.get_name()] = result
        host = result._host
        print(json.dumps({host.name: result._result}, indent=4))
    def v2_runner_on_unreachable(self, result):
        self.host_unreachable[result._host.get_name()] = result

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

    def __init__(self, resource, user, becomeuser, playvars={}, *args, **kwargs):
        self._resource = resource
        self._user = user
        self._becomeuser = becomeuser
        self.inventory = None
        self.playvars = playvars  # add
        self.variable_manager = None
        self.loader = None
        self.options = None
        self.passwords = None
        self.callback = None
        self.__initializeAnsibleData()
        self.results_raw = {}
        
    def __initializeAnsibleData(self):
        Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'timeout', 'remote_user',
                                         'ask_pass', 'private_key_file', 'ssh_common_args', 'ssh_extra_args',
                                         'sftp_extra_args',
                                         'scp_extra_args', 'become', 'become_method', 'become_user', 'ask_value_pass',
                                         'verbosity',
                                         'check', 'listhosts', 'listtasks', 'listtags', 'syntax', 'diff'])
        self.options = Options(connection='ssh', module_path=None, forks=100, timeout=5,
                               remote_user=self._user, ask_pass=False, private_key_file=None, ssh_common_args=None,
                               ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=True,
                               become_method='sudo',
                               become_user=self._becomeuser, ask_value_pass=False, verbosity=None, check=False,
                               listhosts=False,
                               listtasks=False, listtags=False, syntax=False, diff=False)
        self.loader = DataLoader()
        self.passwords = dict(sshpass=None, becomepass=None)
        self.inventory = InventoryManager(loader=self.loader, sources=self._resource)
        self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory)
        self.variable_manager.extra_vars = self.playvars
        
    def run(self, host_list, module_name, module_args, ):
        play_source = dict(
            name="Ansible Play For  At 20190104",
            hosts=host_list,
            gather_facts='no',
            tasks=[
                dict(action=dict(module=module_name, args=module_args))]

        )
        play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)
        tqm = None
        self.callback = ResultCallback()
        try:
            tqm = TaskQueueManager(
                inventory=self.inventory,
                variable_manager=self.variable_manager,
                loader=self.loader,
                options=self.options,
                passwords=self.passwords,
                stdout_callback="default",
               
            )
            tqm._stdout_callback = self.callback
            result = tqm.run(play)  
        finally:
            if tqm is not None:
                tqm.cleanup()
           

    def playbookRun(self, playbook_path):
        from ansible.executor.playbook_executor import PlaybookExecutor

        playbook = PlaybookExecutor(playbooks=playbook_path,
                                    inventory=self.inventory,
                                    variable_manager=self.variable_manager,
                                    loader=self.loader,
                                    options=self.options,
                                    passwords=self.passwords)

        self.callback = ResultCallback()
        playbook._tqm._stdout_callback = self.callback
        try:
            result = playbook.run()
        except AnsibleParserError:
            code = 1001
            results = {'playbook': playbook_path, 'msg': playbook_path + 'playbook have syntax error', 'flag': False}
            return code, results

    def get_result(self):
        self.results_raw = {'success': {}, 'failed': {}, 'unreachable': {}}
        for host, result in self.callback.host_ok.items():
            self.results_raw['success'][host] = result._result

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

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

        return self.results_raw


    def get_result_v2(self):
        self.results_raw = {'success': list(), 'failed': list(), 'unreachable': list()}

        for host, result in self.callback.host_ok.items():
            self.results_raw['success'].append({"ip": host, "result": result._result})

        for host, result in self.callback.host_failed.items():
            self.results_raw['failed'].append({"ip": host, "result": result._result})

        for host, result in self.callback.host_unreachable.items():
            self.results_raw['unreachable'].append({"ip": host, "result": result._result['msg']})
        return self.results_raw


if __name__ == "__main__":
    print("Ansible Api By  20190104 Ansible Version: 2.7.5  Test Ok")

2. Inventory动态主机代码如下;

#!/usr/bin/env python36
"""
@author:lijx
@contact: [email protected]
@site: https://blog.51cto.com/breaklinux
@version: 1.0
"""
from flask import request, Response
import requests
import os
HERE = os.path.abspath(__file__)
HOME_DIR = os.path.split(os.path.split(HERE)[0])[0]
script_path = os.path.join(HOME_DIR, "tools")
def getHostInventoryData(url):
    import json
    gethostdata = requests.get(url)
    getdata = gethostdata.json()["data"]
    data = dict()
    l=[]
    for i in getdata:
        l.append(i["group"])
    groups = set(l)
    gdata=str(groups)
    data["all"] = {"children": gdata}
    data["_meta"] = {"hostvars": {}}
    for group in groups:
        data[group] = dict()
        data[group]["hosts"] = list()
        for x in getdata:
            if x["group"] == group:
               data[group]["hosts"].append(x["instanceip"])
    return json.dumps(data, indent=5)

def HostApi():
    getInventoryUrl = "http://192.168.58.14:5000/ansible/host/v1"
    import json
    import configparser
    data = json.loads(getHostInventoryData(getInventoryUrl))

    config = configparser.ConfigParser(allow_no_value=True)
    for i in data:
        if i != "all" and i != "_meta":
            config.add_section(i)
            for h in data[i]["hosts"]:
                config.set(i, h)
            config.write(open("%s/static_hosts"%script_path, "w"))
    return True


if __name__ == "__main__":
    from optparse import OptionParser
    getInventoryUrl = "http://192.168.58.14:5000/ansible/host/v1"  ###获取动态主机接口###
    parse = OptionParser()
    parse.add_option("-l", "--list", action="store_true", dest="list", default=False)
    (option, arges) = parse.parse_args()
    if option.list:
        print(getHostInventoryData(getInventoryUrl))
    else:
        import json
        print(json.loads(getHostInventoryData(getInventoryUrl)))

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK