从零打造企业内部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/
四.项目内部设计如下图:
五.项目示例代码如下:
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)))