从零打造企业内部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: 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)))
来源:oschina
链接:https://my.oschina.net/u/4309139/blog/3221308