從零打造企業內部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/
四.項目內部設計以下圖:
五.項目示例代碼以下:
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)))