AGENT 模式唯一标识主机名
客户端以自身主机名为唯一标识将数据上报到API,每个客户端数据根据主机名去存储,若主机名被改变则数据会被认为是新主机得数据造成信息上报失误。
-
解决方式
客户端建立配置文件,第一次数据采集后把主机名配置写入配置文件,第二次后以配置文件中主机名为准进行数据上报
-
代码
1 config/settings.py 2 3 CERT_PATH = os.path.join(BASEDIR,'config','cert') 4 5 src/plugins/client.py 6 class Agent(Base): def execute(self): 7 8 server_info = PluginManager().exec_plugin() 9 #唯一标识主机名得处理(在config/cert为记录主机名得文件) 10 hostname = server_info['basic']['data']['hostname'] 11 certname = open(Settings.CERT_PATH,'r',encoding='utf-8').read() 12 if not certname.strip(): #注意去空行。如果文件中没有,第一次会写入获取得主机名 13 with open(Settings.CERT_PATH,'w',encoding='utf-8') as f: 14 f.write(hostname) 15 else: #如果有就以文件中主机名为准 16 server_info['basic']['data']['hostname'] = certname 17 self.post_asset(server_info)
SSH/SALTSTATC 模式的多线程
-
描述
主机数量很多,代理端采用for 循环逐个执行效率低,可以建立一个线程池解决此问题
-
代码
from concurrent.futures import ThreadPoolExecutor #引入线程池 class SSHSALT(Base): def get_host(self): # 获取未采集的主机列表: response = requests.get(Settings.API) result = json.loads(response.text) # "{status:'True',data: ['c1.com','c2.com']}" if not result['status']: return return result['data'] def run(self,host): server_info = PluginManager(host).exec_plugin() self.post_asset(server_info) def execute(self): pool = ThreadPoolExecutor(10) #实例化一个并发量为10得线程池得对象 host_list = self.get_host() for host in host_list: pool.submit(self.run(),host) #一直保持10个任务在同时运行,host为传入self.run()中得参数
Autoserver 服务端
API(数据接收)/backendmanger(后台管理)/repository(数据库管理)
创建django框架 autoserver ,启动服务通过app API实时接收主机数据
autoserver/autoserver/urls.py from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^api/', include('api.urls')), ] autoserver/api/urls.py from django.conf.urls import url,include from django.contrib import admin from api import views urlpatterns = [ url(r'^asset.html$', views.asset), ] autoserver/api/views.py import json from django.shortcuts import render,HttpResponse from repository import models def asset(request): if request.method == 'POST': # 新资产信息 server_info = json.loads(request.body.decode('utf-8')) #数据为bytes格式需要解码 hostname = server_info['basic']['data']['hostname'] #采集数据中的主机名 server_obj = models.Server.objects.filter(hostname=hostname).first() #查询数据库中是否有此主机名的记录 if not server_obj: return HttpResponse('当前主机名在资产中未录入') asset_obj = server_obj.asset #server与asset通过asset 一对一映射关系
数据采集端代码
cmdb/config/settings.py API = "http://127.0.0.1:8000/api/asset.html" cmdb/src/client.py .....
API 接收数据的处理及入库
数据库表结构
表 server 与表disk cpu memory 是一对多的关系,server中记录hostname ,每个server 有多个disk 、cpu、memory ...
数据入库逻辑顺序
新资产上架,hostname 等信息是web管理界面手动输入,其他如disk cpu memory 是数据采集通过API入库,数据采集的主机名与数据库中一致时入库数据,不一致则不入库采集数据
采集数据处理
disk cpu memory 等每个主机有多个相关信息,例如磁盘,磁盘的个数存在增加删除磁盘大小变更等情况,所有入库前采集数据与数据库中数据进行数据比对。由于每个磁盘都有插巢,所有在以id 标识每个插巢,数据对比处理以插巢id 为基准
""" 1. 根据新资产和原资产进行比较:新["5","1"] 老["4","5","6"] 2. 增加: [1,] 更新:[5,] 删除:[4,6] 3. 增加: server_info中根据[1,],找到资产详细:入库 删除: 数据库中找当前服务器的硬盘:[4,6] 更新:[5,] disk_list = [obj,obj,obj] { 'data': { '5': {'slot': '5', 'capacity': '476.939', 'pd_type': 'SATA', 'model': 'S1AXNSAFB00549A Samsung SSD 840 PRO Series DXM06B0Q'}, '3': {'slot': '3', 'capacity': '476.939', 'pd_type': 'SATA', 'model': 'S1AXNSAF912433K Samsung SSD 840 PRO Series DXM06B0Q'}, '4': {'slot': '4', 'capacity': '476.939', 'pd_type': 'SATA', 'model': 'S1AXNSAF303909M Samsung SSD 840 PRO Series DXM05B0Q'}, '0': {'slot': '0', 'capacity': '279.396', 'pd_type': 'SAS', 'model': 'SEAGATE ST300MM0006 LS08S0K2B5NV'}, '2': {'slot': '2', 'capacity': '476.939', 'pd_type': 'SATA', 'model': 'S1SZNSAFA01085L Samsung SSD 850 PRO 512GB EXM01B6Q'}, '1': {'slot': '1', 'capacity': '279.396', 'pd_type': 'SAS', 'model': 'SEAGATE ST300MM0006 LS08S0K2B5AH'} }, 'status': True } log_list = [] #创建日志列表用于存储增删该查等日志记录 dict_info = {'slot': '5', 'capacity': '476.939', 'pd_type': 'SATA', 'model': 'S1AXNSAFB00549A Samsung SSD 840 PRO Series DXM06B0Q'}, obj if obj.capacity != dict_info['capacity']: log_list.append('硬盘容量由%s变更为%s' %s(obj.capacity,dict_info['capacity']) obj.capacity = dict_info['capacity'] ... obj.save() models.xxx.object.create(detail=''.join(log_list)) """