從零打造企業內部Ansible自動化管理平臺-第一章(Api)

                                                                從零打造企業內部Ansible自動化管理平臺-第一章html


一. 背景;python

      隨着中下企業技術的快速技術迭代,以及微服務分佈式架構的普及,傳統運維繫統運維環境治理方面,系統初始化,環境部署,環境一致性困難較大. 由此      ansible是新出現的自動化運維工具,基於Python開發,集合了衆多運維工具(puppet、cfengine、chef、func、fabric)的優勢,linux

      實現了批量系統配置、批量程序部署、環境快速部署迭代,批量運行命令等功能。git

       Ansible 工做原理和關聯模塊介紹:github

        ansible是基於模塊工做的,自己沒有批量部署的能力。真正具備批量部署的是ansible所運行的模塊,ansible只是提供一種框架。主要包括:json

        (1)、鏈接插件connection plugins:負責和被監控端實現通訊;flask

        (2)、host inventory:指定操做的主機,是一個配置文件裏面定義監控的主機;api

        (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: 360595252@qq.com    
@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: 360595252@qq.com
@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)))
相關文章
相關標籤/搜索