一 发送数据到api(Django的URL)
发送请求携带参数
requests.get(url='http://127.0.0.1:8000/api/asset/?k1=123') # <QueryDict: {'k1': ['123']}> requests.get(url='http://127.0.0.1:8000/api/asset/',params={'k1':'v1','k2':'v2'}) # <QueryDict: {'k2': ['v2'], 'k1': ['v1']}>
requests.post( url='http://127.0.0.1:8000/api/asset/', params={'k1':'v1','k2':'v2'}, # GET形式传值 URL<QueryDict: {'k2': ['v2'], 'k1': ['v1']}> data={'username':'1123','pwd': '666'}, # POST形式传值 请求体 <QueryDict: {'pwd': ['666'], 'username': ['1123']}> headers={'a':'123'} # 请求头数据 ) requests.body b'username=1123&pwd=666'
api需要post请求,并且有一定的数据格式
# 数据格式 host_data = { 'status': True, 'data':{ 'hostname': 'c1.com', 'disk': {'status':True,'data': 'xxx'}, 'mem': {'status':True,'data': 'xxx'}, 'nic': {'status':True,'data': 'xxx'}, } } # 模拟给API发送资产信息 response = requests.post( url='http://127.0.0.1:8000/api/asset/', # 序列化 # data=host_data, # 列表 <QueryDict: {'data': ['nic', 'disk', 'hostname', 'mem'], 'status': ['True']}> json=host_data, # reuest.body 里面 # 字典 b'{"status": true, # "data": { # "disk": {"status": true, "data": "xxx"}, # "nic": {"status": true, "data": "xxx"}, # "hostname": "c1.com", # "mem": {"status": true, "data": "xxx"}} # }' ) print(response.text) # 得到是 django执行的返回值 ...
而我们客户端传送这样的数据格式的时候,用到了lib下的serialize,response俩个模块来对数据进行格式化
#!/usr/bin/env python # -*- coding:utf-8 -*- class BaseResponse(object): def __init__(self): self.status = True self.message = None self.data = None self.error = None
每一个资产信息都继承了response这个模块,最终得到一个对象,如下
{ status = True message = None data = os_platform:'',os_version:'',hostname:'','cpu':OBJ,'disk':OBJ} 这个OBJ会在交给自己写的JSON.dump去处理 error = None }
然后经过serialize模块处理
#!/usr/bin/env python # -*- coding:utf-8 -*- import json as default_json from json.encoder import JSONEncoder from .response import BaseResponse # 例子来源于本目录TEST {"k1": 123, "k2": "2018-03-13 18", "k3": {"status": true, "data": "asdf"}} class JsonEncoder(JSONEncoder): # O 就是字典的VULe def default(self, o): if isinstance(o, BaseResponse): # 用O.__DICT__处理 { "k3": {"status": true, "data": "asdf"}} 字典套字典 return o.__dict__ # 用默认的数据类型 return JSONEncoder.default(self, o) # 自己写的JSON数,JSON.DUMP 只能序列PYTHON内部数据格式,对象不行,时间对象 class Json(object): @staticmethod def dumps(response, ensure_ascii=True): # cls=JsonEncoder 自定义序列化 return default_json.dumps(response, ensure_ascii=ensure_ascii, cls=JsonEncoder) # 传过来的是response.date,也就是说传过来的是 '''{ data = {os_platform:'',os_version:'',hostname:'','cpu':OBJ} 这个OBJ是BaseResponse对象,所以格式化成 cpu:{ self.status = True self.message = None self.data = None self.error = None } }'''
这样我就拿到了一个json数据,格式如下
{ "disk": { "message": null, "error": null, "data": { "0": { "model": "SEAGATE ST300MM0006 LS08S0K2B5NV", "capacity": "279.396", "pd_type": "SAS", "slot": "0" }, "5": { "model": "S1AXNSAFB00549A Samsung SSD 840 PRO Series DXM06B0Q", "capacity": "476.939", "pd_type": "SATA", "slot": "5" }, "4": { "model": "S1AXNSAF303909M Samsung SSD 840 PRO Series DXM05B0Q", "capacity": "476.939", "pd_type": "SATA", "slot": "4" }, "3": { "model": "S1AXNSAF912433K Samsung SSD 840 PRO Series DXM06B0Q", "capacity": "476.939", "pd_type": "SATA", "slot": "3" }, "2": { "model": "S1SZNSAFA01085L Samsung SSD 850 PRO 512GB EXM01B6Q", "capacity": "476.939", "pd_type": "SATA", "slot": "2" }, "1": { "model": "SEAGATE ST300MM0006 LS08S0K2B5AH", "capacity": "279.396", "pd_type": "SAS", "slot": "1" } }, "status": true }, "os_version": "CentOS release 6.6 (Final)", "os_platform": "linux", "hostname": "bj.com" }
api处接受到请求的处理
if request.method == 'POST': # GET 模式不用走这里,因为BODY 里面没有值,肯定会报错 import json host_info = json.loads(str(request.body,encoding='utf-8')) print(host_info) } return HttpResponse('....')
二 api验证
第一种:发送一个字符串auth_key
1. 首先可以发送请求的时候,发过来一个验证token
host_data = { 'status': True, 'data':{ 'hostname': 'c1.com', 'disk': {'status':True,'data': 'xxx'}, 'mem': {'status':True,'data': 'xxx'}, 'nic': {'status':True,'data': 'xxx'}, } } # 模拟给API发送资产信息 response = requests.post( url='http://127.0.0.1:8000/api/asset/', # 序列化 json=host_data, }' # 模拟发送个验证TOKEN headers={'authkey': '123456'} ) print(response.text) # 得到是 django执行的返回值 ...
2. 在api处获取到这个token,进行校验,在处理post请求数据
from django.shortcuts import render, HttpResponse from django.views.decorators.csrf import csrf_exempt, csrf_protect @csrf_exempt def asset(request): auth_key = request.GET.get('HTTP_AUTHKEY') auth_key = request.META['HTTP_AUTHKEY'] # 会存在这里面反过来的KEY ck = 123456 if auth_key != ck: return HttpResponse('授权失败') if request.method == 'POST': # GET 模式不用走这里,因为BODY 里面没有值,肯定会报错 import json host_info = json.loads(str(request.body,encoding='utf-8')) print(host_info) # {'status': True, # 'data': { # 'hostname': 'c1.com', # 'mem': {'status': True, 'data': 'xxx'}, # 'disk': {'status': True, 'data': 'xxx'}, # 'nic': {'status': True, 'data': 'xxx'}} # } return HttpResponse('....')
存在的问题就是,有可能这个请求被截胡,很可能会被其他人获取到这个token
第二种:md5加密字符串 很可能会被其他人获取到这个token
## MD5加密的验证TOKEN appid = '123456' m = hashlib.md5() m.update(bytes(appid,encoding='utf-8')) authkey = m.hexdigest() print(authkey) # e10adc3949ba59abbe56e057f20f883e host_data = { 'status': True, 'data':{ 'hostname': 'c1.com', 'disk': {'status':True,'data': 'xxx'}, 'mem': {'status':True,'data': 'xxx'}, 'nic': {'status':True,'data': 'xxx'}, } } # 模拟给API发送资产信息 response = requests.post( url='http://127.0.0.1:8000/api/asset/', # 序列化 # data=host_data, # 列表 <QueryDict: {'data': ['nic', 'disk', 'hostname', 'mem'], 'status': ['True']}> json=host_data, # reuest.body 里面 # 字典 b'{"status": true, # 模拟发送个验证TOKEN headers={'authkey': authkey} ) print(response.text) # 得到是 django执行的返回值 ...
from django.shortcuts import render, HttpResponse from django.views.decorators.csrf import csrf_exempt, csrf_protect @csrf_exempt def asset(request): print(request.method) print(request.POST) print(request.GET) print(request.body) auth_key = request.GET.get('HTTP_AUTHKEY') auth_key = request.META['HTTP_AUTHKEY'] # 会存在这里面反过来的KEY ck = 123456 if auth_key != ck: return HttpResponse('授权失败') if request.method == 'POST': # GET 模式不用走这里,因为BODY 里面没有值,肯定会报错 import json host_info = json.loads(str(request.body,encoding='utf-8')) print(host_info) # {'status': True, # 'data': { # 'hostname': 'c1.com', # 'mem': {'status': True, 'data': 'xxx'}, # 'disk': {'status': True, 'data': 'xxx'}, # 'nic': {'status': True, 'data': 'xxx'}} # } return HttpResponse('....') # 获取到的数据格式 # request.body 内容 # 字典 b'{"status": true, # "data": { # "disk": {"status": true, "data": "xxx"}, # "nic": {"status": true, "data": "xxx"}, # "hostname": "c1.com", # "mem": {"status": true, "data": "xxx"}} # }'
第三种:md5时间动态加密字符串 漏洞更多,很可能会被其他人获取到这个token,可以访问很多的url
# 时间动态加密 current_time = time.time() app_id = "8kasoimnasodn8687asdfkmasdf" app_id_time = "%s|%s" %(app_id,current_time,) m = hashlib.md5() m.update(bytes(app_id_time,encoding='utf-8')) authkey = m.hexdigest() # 将加密验证TOKEN和时间带过去 authkey_time = "%s|%s" %(authkey,current_time,) print(authkey_time) # 2746e6acc0c36f31d68dd6a166b434be|1520910092.340296 host_data = { 'status': True, 'data':{ 'hostname': 'c1.com', 'disk': {'status':True,'data': 'xxx'}, 'mem': {'status':True,'data': 'xxx'}, 'nic': {'status':True,'data': 'xxx'}, } } # 模拟给API发送资产信息 response = requests.post( url='http://127.0.0.1:8000/api/asset/', # 序列化 json=host_data, # reuest.body 里面 # 字典 b'{"status": true, # 模拟发送个验证TOKEN headers={'authkey': authkey_time} ) print(response.text) # 得到是 django执行的返回值 ...
from django.shortcuts import render, HttpResponse from django.views.decorators.csrf import csrf_exempt, csrf_protect import hashlib import time ck = "8kasoimnasodn8687asdfkmasdf" auth_list = [] @csrf_exempt def asset(request): # 发过来的验证TOKEN auth_key:2746e6acc0c36f31d68dd6a166b434be|client_ctime:1520910092.340296 # 客户端发过来的时间验证 auth_key_time = request.META['HTTP_AUTHKEY'] auth_key_client, client_ctime = auth_key_time.split('|') # 我这里的时间验证 key_time = "%s|%s" % (ck, client_ctime,) m = hashlib.md5() m.update(bytes(key_time, encoding='utf-8')) authkey = m.hexdigest() if authkey != auth_key_client: # 判断 2次加密后的TOKEN return HttpResponse('授权失败') return HttpResponse('....')
第四种:通过时间规则限制,模仿cookie
# 时间动态加密 current_time = time.time() app_id = "8kasoimnasodn8687asdfkmasdf" app_id_time = "%s|%s" %(app_id,current_time,) m = hashlib.md5() m.update(bytes(app_id_time,encoding='utf-8')) authkey = m.hexdigest() # 将加密验证TOKEN和时间带过去 authkey_time = "%s|%s" %(authkey,current_time,) print(authkey_time) # 2746e6acc0c36f31d68dd6a166b434be|1520910092.340296 host_data = { 'status': True, 'data':{ 'hostname': 'c1.com', 'disk': {'status':True,'data': 'xxx'}, 'mem': {'status':True,'data': 'xxx'}, 'nic': {'status':True,'data': 'xxx'}, } } # 模拟给API发送资产信息 response = requests.post( url='http://127.0.0.1:8000/api/asset/', # 序列化 json=host_data, # reuest.body 里面 # 字典 b'{"status": true, # 模拟发送个验证TOKEN headers={'authkey': authkey_time} ) print(response.text) # 得到是 django执行的返回值 ...
from django.shortcuts import render, HttpResponse from django.views.decorators.csrf import csrf_exempt, csrf_protect import hashlib import time ck = "8kasoimnasodn8687asdfkmasdf" # 访问时间列表,应该设置过期时间,MEMCACHE,REDIS都可以做 auth_list = [] @csrf_exempt def asset(request): # 发过来的验证TOKEN 客户端发过来的时间验证 auth_key_time = request.META['HTTP_AUTHKEY'] # auth_key_client:2746e6acc0c36f31d68dd6a166b434be | client_ctime:1520910092.340296 auth_key_client, client_ctime = auth_key_time.split('|') # 1。时间规则 久远排除掉 server_current_time = time.time() if server_current_time - 5 > float(client_ctime): return HttpResponse('时间太久远了') # 2。是不是来过 if auth_key_time in auth_list: return HttpResponse('已经访问过了,所以你是木马') # 3。我这里的时间验证 key_time = "%s|%s" % (ck, client_ctime,) m = hashlib.md5() m.update(bytes(key_time, encoding='utf-8')) authkey = m.hexdigest() if authkey != auth_key_client: return HttpResponse('授权失败') # 访问成功 auth_list.append(auth_key_time) print(auth_list) return HttpResponse('....')
三 表结构
from django.db import models class UserProfile(models.Model): """ 用户信息 """ name = models.CharField(u'姓名', max_length=32) email = models.EmailField(u'邮箱') phone = models.CharField(u'座机', max_length=32) mobile = models.CharField(u'手机', max_length=32) class Meta: verbose_name_plural = "用户表" def __str__(self): return self.name class AdminInfo(models.Model): """ 用户登陆相关信息 """ user_info = models.OneToOneField("UserProfile") username = models.CharField(u'用户名', max_length=64) password = models.CharField(u'密码', max_length=64) class Meta: verbose_name_plural = "管理员表" def __str__(self): return self.user_info.name class UserGroup(models.Model): """ 用户组 """ name = models.CharField(max_length=32, unique=True) users = models.ManyToManyField('UserProfile') class Meta: verbose_name_plural = "用户组表" def __str__(self): return self.name class BusinessUnit(models.Model): """ 业务线 """ name = models.CharField('业务线', max_length=64, unique=True) contact = models.ForeignKey('UserGroup', verbose_name='业务联系人', related_name='c') # 多个人 manager = models.ForeignKey('UserGroup', verbose_name='系统管理员', related_name='m') # 多个人 class Meta: verbose_name_plural = "业务线表" def __str__(self): return self.name class IDC(models.Model): """ 机房信息 """ name = models.CharField('机房', max_length=32) floor = models.IntegerField('楼层', default=1) class Meta: verbose_name_plural = "机房表" def __str__(self): return self.name class Tag(models.Model): """ 资产标签 """ name = models.CharField('标签', max_length=32, unique=True) class Meta: verbose_name_plural = "标签表" def __str__(self): return self.name class Asset(models.Model): """ 资产信息表,所有资产公共信息(交换机,服务器,防火墙等) """ device_type_choices = ( (1, '服务器'), (2, '交换机'), (3, '防火墙'), ) device_status_choices = ( (1, '上架'), (2, '在线'), (3, '离线'), (4, '下架'), ) device_type_id = models.IntegerField(choices=device_type_choices, default=1) device_status_id = models.IntegerField(choices=device_status_choices, default=1) cabinet_num = models.CharField('机柜号', max_length=30, null=True, blank=True) cabinet_order = models.CharField('机柜中序号', max_length=30, null=True, blank=True) idc = models.ForeignKey('IDC', verbose_name='IDC机房', null=True, blank=True) business_unit = models.ForeignKey('BusinessUnit', verbose_name='属于的业务线', null=True, blank=True) tag = models.ManyToManyField('Tag') latest_date = models.DateField(null=True) create_at = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = "资产表" def __str__(self): return "%s-%s-%s" % (self.idc.name, self.cabinet_num, self.cabinet_order) class Server(models.Model): """ 服务器信息 """ asset = models.OneToOneField('Asset') hostname = models.CharField(max_length=128, unique=True) sn = models.CharField('SN号', max_length=64, db_index=True) manufacturer = models.CharField(verbose_name='制造商', max_length=64, null=True, blank=True) model = models.CharField('型号', max_length=64, null=True, blank=True) manage_ip = models.GenericIPAddressField('管理IP', null=True, blank=True) os_platform = models.CharField('系统', max_length=16, null=True, blank=True) os_version = models.CharField('系统版本', max_length=16, null=True, blank=True) cpu_count = models.IntegerField('CPU个数', null=True, blank=True) cpu_physical_count = models.IntegerField('CPU物理个数', null=True, blank=True) cpu_model = models.CharField('CPU型号', max_length=128, null=True, blank=True) create_at = models.DateTimeField(auto_now_add=True, blank=True) class Meta: verbose_name_plural = "服务器表" def __str__(self): return self.hostname class NetworkDevice(models.Model): asset = models.OneToOneField('Asset') management_ip = models.CharField('管理IP', max_length=64, blank=True, null=True) vlan_ip = models.CharField('VlanIP', max_length=64, blank=True, null=True) intranet_ip = models.CharField('内网IP', max_length=128, blank=True, null=True) sn = models.CharField('SN号', max_length=64, unique=True) manufacture = models.CharField(verbose_name=u'制造商', max_length=128, null=True, blank=True) model = models.CharField('型号', max_length=128, null=True, blank=True) port_num = models.SmallIntegerField('端口个数', null=True, blank=True) device_detail = models.CharField('设置详细配置', max_length=255, null=True, blank=True) class Meta: verbose_name_plural = "网络设备" class Disk(models.Model): """ 硬盘信息 """ slot = models.CharField('插槽位', max_length=8) model = models.CharField('磁盘型号', max_length=32) capacity = models.FloatField('磁盘容量GB') pd_type = models.CharField('磁盘类型', max_length=32) server_obj = models.ForeignKey('Server',related_name='disk') class Meta: verbose_name_plural = "硬盘表" def __str__(self): return self.slot class NIC(models.Model): """ 网卡信息 """ name = models.CharField('网卡名称', max_length=128) hwaddr = models.CharField('网卡mac地址', max_length=64) netmask = models.CharField(max_length=64) ipaddrs = models.CharField('ip地址', max_length=256) up = models.BooleanField(default=False) server_obj = models.ForeignKey('Server',related_name='nic') class Meta: verbose_name_plural = "网卡表" def __str__(self): return self.name class Memory(models.Model): """ 内存信息 """ slot = models.CharField('插槽位', max_length=32) manufacturer = models.CharField('制造商', max_length=32, null=True, blank=True) model = models.CharField('型号', max_length=64) capacity = models.FloatField('容量', null=True, blank=True) sn = models.CharField('内存SN号', max_length=64, null=True, blank=True) speed = models.CharField('速度', max_length=16, null=True, blank=True) server_obj = models.ForeignKey('Server',related_name='memory') class Meta: verbose_name_plural = "内存表" def __str__(self): return self.slot class AssetRecord(models.Model): """ 资产变更记录,creator为空时,表示是资产汇报的数据。 """ asset_obj = models.ForeignKey('Asset', related_name='ar') content = models.TextField(null=True) creator = models.ForeignKey('UserProfile', null=True, blank=True) create_at = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = "资产记录表" def __str__(self): return "%s-%s-%s" % (self.asset_obj.idc.name, self.asset_obj.cabinet_num, self.asset_obj.cabinet_order) class ErrorLog(models.Model): """ 错误日志,如:agent采集数据错误 或 运行错误 """ asset_obj = models.ForeignKey('Asset', null=True, blank=True) title = models.CharField(max_length=16) content = models.TextField() create_at = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = "错误日志表" def __str__(self): return self.title
表结构创建好了之后,登陆到admin添加信息
-- 用户,用户组,业务线,机房 可以提前添加
-- 数据库和收集来的资产数据对比
新数据又,数据库没有—新增
数据库有。新数据没有 — 拔走
数据库也有,新数据也有,但是数据不一样 — 更新
-- 我们变更数据库信息的时候建议
应该先有一些基本信息,然后在汇报的时候再有详细信息 资产 - 服务器(主机名,序列号...)
四 数据库资产变更
@method_decorator(auth.api_auth) # 装饰器,必须执行api_auth,规则限制 def post(self, request, *args, **kwargs): """ 更新或者添加资产信息 :param request: :param args: :param kwargs: :return: 1000 成功;1001 接口授权失败;1002 数据库中资产不存在 """ server_info = json.loads(request.body.decode('utf-8')) server_info = json.loads(server_info) # 有一步测试,将RET返回 遇到问题。第一种新加。第二种,是不是应该先有一些基本信息,然后在汇报的时候再有详细信息 资产-服务器 # ret = {'code': 1000, 'message': ''} # print(server_info) # server_info 最新汇报服务器所有信息 hostname = server_info['hostname'] ret = {'code': 1000, 'message': '[%s]更新完成' % hostname} # 根据主机名去数据库中获取相关信息 server_obj = models.Server.objects.filter(hostname=hostname).select_related('asset').first() # 如果数据库没有这个主机,我们不录入 if not server_obj: ret['code'] = 1002 ret['message'] = '[%s]资产不存在' % hostname return JsonResponse(ret) # 数据库变更 for k,v in config.PLUGINS_DICT.items(): module_path,cls_name = v.rsplit('.',1) cls = getattr(importlib.import_module(module_path),cls_name) response = cls.process(server_obj,server_info,None) if not response.status: ret['code'] = 1003 ret['message'] = '[%s]资产变更异常' % hostname if hasattr(cls,'update_last_time'): cls.update_last_time(server_obj,None) # ========》 server_obj服务器对象 ;server_info 《========== # 硬盘 或 网卡 或 内存 # 硬盘:增删改 # 1. server_obj反向关联硬盘表,获取数据库中硬盘信息 # [ # {'slot': "#1", 'size': '100'}, # {'slot': "#2", 'size': '60'}, # {'slot': "#3", 'size': '88'}, # ] # old_list = ['#1','#2','#3'] # 2. server_info['disk'] 新汇报的硬盘数据 # { # "#1":{'slot': "#1", 'size': '90'}, # "#4":{'slot': "#4", 'size': '40'}, # } # new_list = ['#1','#4'] #3. 更新['#1'] 删除['#2','#3'] 增加 ['#4'] #4. # 增加 ['#4'] """ for i in ['#4']: data_dict = dic[i] models.Diks.objces.create(**data_dict) """ return JsonResponse(ret)
#!/usr/bin/env python # -*- coding:utf-8 -*- import traceback import datetime from utils.response import BaseResponse from utils import agorithm from repository import models from django.db.models import Q import datetime def get_untreated_servers(): response = BaseResponse() try: current_date = datetime.date.today() condition = Q() # 今日未采集的资产 con_date = Q() con_date.connector = 'OR' con_date.children.append(("asset__latest_date__lt", current_date)) con_date.children.append(("asset__latest_date", None)) # 在线状态的服务器 con_status = Q() con_status.children.append(('asset__device_status_id', '2')) condition.add(con_date, 'AND') condition.add(con_status, 'AND') result = models.Server.objects.filter(condition).values('hostname') response.data = list(result) response.status = True except Exception as e: response.message = str(e) models.ErrorLog.objects.create(asset_obj=None, title='get_untreated_servers', content=traceback.format_exc()) return response # ############# 操作基本信息(cpu和主板) ############# # 操作基本,并记录操作日志 # 更新cpu和主板信息 class HandleBasic(object): # 处理基本信息,包括主板和CPU信息 @staticmethod def process(server_obj, server_info, user_obj): response = BaseResponse() try: log_list = [] main_board = server_info['main_board']['data'] cpu = server_info['cpu']['data'] if server_obj.os_platform != server_info['os_platform']: log_list.append('系统由%s变更为%s' % (server_obj.os_platform, server_info['os_platform'],)) server_obj.os_platform = server_info['os_platform'] if server_obj.os_version != server_info['os_version']: log_list.append(u'系统版本由%s变更为%s' % (server_obj.os_version, server_info['os_version'],)) server_obj.os_version = server_info['os_version'] if server_obj.sn != main_board['sn']: log_list.append(u'主板SN号由%s变更为%s' % (server_obj.sn, main_board['sn'],)) server_obj.sn = main_board['sn'] if server_obj.manufacturer != main_board['manufacturer']: log_list.append(u'主板厂商由%s变更为%s' % (server_obj.manufacturer, main_board['manufacturer'],)) server_obj.manufacturer = main_board['manufacturer'] if server_obj.model != main_board['model']: log_list.append(u'主板型号由%s变更为%s' % (server_obj.model, main_board['model'],)) server_obj.model = main_board['model'] if server_obj.cpu_count != cpu['cpu_count']: log_list.append(u'CPU逻辑核数由%s变更为%s' % (server_obj.cpu_count, cpu['cpu_count'],)) server_obj.cpu_count = cpu['cpu_count'] if server_obj.cpu_physical_count != cpu['cpu_physical_count']: log_list.append( u'CPU物理核数由%s变更为%s' % (server_obj.cpu_physical_count, cpu['cpu_physical_count'],)) server_obj.cpu_physical_count = cpu['cpu_physical_count'] if server_obj.cpu_model != cpu['cpu_model']: log_list.append(u'CPU型号由%s变更为%s' % (server_obj.cpu_model, cpu['cpu_model'],)) server_obj.cpu_model = cpu['cpu_model'] server_obj.save() if log_list: models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content=';'.join(log_list)) except Exception as e: response.status = False models.ErrorLog.objects.create(asset_obj=server_obj.asset, title='basic-run', content=traceback.format_exc()) return response @staticmethod def update_last_time(server_obj, user_obj): response = BaseResponse() try: current_date = datetime.date.today() server_obj.asset.latest_date = current_date server_obj.asset.save() models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content='资产汇报') except Exception as e: response.status = False models.ErrorLog.objects.create(asset_obj=server_obj.asset, title='basic-run', content=traceback.format_exc()) return response # ############# 操作网卡信息 ############# # 操作网卡,并记录操作日志 # 添加网卡 # 删除网卡 # 更新网卡信息 class HandleNic(object): @staticmethod def process(server_obj, server_info, user_obj): response = BaseResponse() try: # 获取数据库中的所有网卡信息 # server_info,服务器最新汇报的数据 server_info['nic'] nic_info = server_info['nic'] if not nic_info['status']: response.status = False models.ErrorLog.objects.create(asset_obj=server_obj.asset, title='nic-agent', content=nic_info['error']) return response client_nic_dict = nic_info['data'] nic_obj_list = models.NIC.objects.filter(server_obj=server_obj) nic_name_list = map(lambda x: x, (item.name for item in nic_obj_list)) update_list = agorithm.get_intersection(set(client_nic_dict.keys()), set(nic_name_list)) add_list = agorithm.get_exclude(client_nic_dict.keys(), update_list) del_list = agorithm.get_exclude(nic_name_list, update_list) # ==> 要删除、更新,添加 HandleNic._add_nic(add_list, client_nic_dict, server_obj, user_obj) HandleNic._update_nic(update_list, nic_obj_list, client_nic_dict, server_obj, user_obj) HandleNic._del_nic(del_list, nic_obj_list, server_obj, user_obj) except Exception as e: response.status = False models.ErrorLog.objects.create(asset_obj=server_obj.asset, title='nic-run', content=traceback.format_exc()) return response @staticmethod def _add_nic(add_list, client_nic_dict, server_obj, user_obj): for item in add_list: cur_nic_dict = client_nic_dict[item] cur_nic_dict['name'] = item log_str = '[新增网卡]{name}:mac地址为{hwaddr};状态为{up};掩码为{netmask};IP地址为{ipaddrs}'.format(**cur_nic_dict) cur_nic_dict['server_obj'] = server_obj models.NIC.objects.create(**cur_nic_dict) models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content=log_str) @staticmethod def _del_nic(del_list, nic_objs, server_obj, user_obj): for item in nic_objs: if item.name in del_list: log_str = '[移除网卡]{name}:mac地址为{hwaddr};状态为{up};掩码为{netmask};IP地址为{ipaddrs}'.format(**item.__dict__) item.delete() models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content=log_str) @staticmethod def _update_nic(update_list, nic_objs, client_nic_dict, server_obj, user_obj): for item in nic_objs: if item.name in update_list: log_list = [] new_hwaddr = client_nic_dict[item.name]['hwaddr'] if item.hwaddr != new_hwaddr: log_list.append(u"[更新网卡]%s:mac地址由%s变更为%s" % (item.name, item.hwaddr, new_hwaddr)) item.hwaddr = new_hwaddr new_up = client_nic_dict[item.name]['up'] if item.up != new_up: log_list.append(u"[更新网卡]%s:状态由%s变更为%s" % (item.name, item.up, new_up)) item.up = new_up new_netmask = client_nic_dict[item.name]['netmask'] if item.netmask != new_netmask: log_list.append(u"[更新网卡]%s:掩码由%s变更为%s" % (item.name, item.netmask, new_netmask)) item.netmask = new_netmask new_ipaddrs = client_nic_dict[item.name]['ipaddrs'] if item.ipaddrs != new_ipaddrs: log_list.append(u"[更新网卡]%s:IP地址由%s变更为%s" % (item.name, item.ipaddrs, new_ipaddrs)) item.ipaddrs = new_ipaddrs item.save() if log_list: models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content=';'.join(log_list)) # ############# 操作内存信息 ############# # 操作内存,并记录操作日志 # 添加内存 # 删除内存 # 更新内存信息 class HandleMemory(object): @staticmethod def process(server_obj, server_info, user_obj): response = BaseResponse() try: mem_info = server_info['memory'] if not mem_info['status']: models.ErrorLog.objects.create(asset_obj=server_obj.asset, title='memory-agent', content=mem_info['error']) response.status = False return response client_mem_dict = mem_info['data'] mem_obj_list = models.Memory.objects.filter(server_obj=server_obj) mem_slots = map(lambda x: x, (item.slot for item in mem_obj_list)) update_list = agorithm.get_intersection(set(client_mem_dict.keys()), set(mem_slots)) add_list = agorithm.get_exclude(client_mem_dict.keys(), update_list) del_list = agorithm.get_exclude(mem_slots, update_list) HandleMemory._add_memory(add_list, client_mem_dict, server_obj, user_obj) HandleMemory._update_memory(update_list, mem_obj_list, client_mem_dict, server_obj, user_obj) HandleMemory._del_memory(del_list, mem_obj_list, server_obj, user_obj) except Exception as e: response.status = False models.ErrorLog.objects.create(asset_obj=server_obj.asset, title='memory-run', content=traceback.format_exc()) return response @staticmethod def _add_memory(add_list, client_mem_dict, server_obj, user_obj): for item in add_list: cur_mem_dict = client_mem_dict[item] log_str = '[新增内存]插槽为{slot};容量为{capacity};类型为{model};速度为{speed};厂商为{manufacturer};SN号为{sn}'.format( **cur_mem_dict) cur_mem_dict['server_obj'] = server_obj models.Memory.objects.create(**cur_mem_dict) models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content=log_str) @staticmethod def _del_memory(del_list, mem_objs, server_obj, user_obj): for item in mem_objs: if item.slot in del_list: log_str = '[移除内存]插槽为{slot};容量为{capacity};类型为{model};速度为{speed};厂商为{manufacturer};SN号为{sn}'.format( **item.__dict__) item.delete() models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content=log_str) @staticmethod def _update_memory(update_list, mem_objs, client_mem_dict, server_obj, user_obj): for item in mem_objs: if item.slot in update_list: log_list = [] new_manufacturer = client_mem_dict[item.slot]['manufacturer'] if item.manufacturer != new_manufacturer: log_list.append(u"[更新内存]%s:厂商由%s变更为%s" % (item.slot, item.manufacturer, new_manufacturer)) item.manufacturer = new_manufacturer new_model = client_mem_dict[item.slot]['model'] if item.model != new_model: log_list.append(u"[更新内存]%s:型号由%s变更为%s" % (item.slot, item.model, new_model)) item.model = new_model new_capacity = client_mem_dict[item.slot]['capacity'] if item.capacity != new_capacity: log_list.append(u"[更新内存]%s:容量由%s变更为%s" % (item.slot, item.capacity, new_capacity)) item.capacity = new_capacity new_sn = client_mem_dict[item.slot]['sn'] if item.sn != new_sn: log_list.append(u"[更新内存]%s:SN号由%s变更为%s" % (item.slot, item.sn, new_sn)) item.sn = new_sn new_speed = client_mem_dict[item.slot]['speed'] if item.speed != new_speed: log_list.append(u"[更新内存]%s:速度由%s变更为%s" % (item.slot, item.speed, new_speed)) item.speed = new_speed item.save() if log_list: models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content=';'.join(log_list)) # ############# 操作硬盘信息 ############# # 操作硬盘,并记录操作日志 # 添加硬盘 # 删除硬盘 # 更新硬盘信息 class HandleDisk(object): @staticmethod def process(server_obj, server_info, user_obj): response = BaseResponse() try: disk_info = server_info['disk'] if not disk_info['status']: response.status = False models.ErrorLog.objects.create(asset_obj=server_obj.asset, title='disk-agent', content=disk_info['error']) return response client_disk_dict = disk_info['data'] disk_obj_list = models.Disk.objects.filter(server_obj=server_obj) disk_slots = map(lambda x: x, (item.slot for item in disk_obj_list)) update_list = agorithm.get_intersection(set(client_disk_dict.keys()), set(disk_slots)) add_list = agorithm.get_exclude(client_disk_dict.keys(), update_list) del_list = agorithm.get_exclude(disk_slots, update_list) HandleDisk._add_disk(add_list, client_disk_dict, server_obj, user_obj) HandleDisk._update_disk(update_list, disk_obj_list, client_disk_dict, server_obj, user_obj) HandleDisk._del_disk(del_list, disk_obj_list, server_obj, user_obj) except Exception as e: response.status = False models.ErrorLog.objects.create(asset_obj=server_obj.asset, title='disk-run', content=traceback.format_exc()) return response @staticmethod def _add_disk(add_list, client_disk_dict, server_obj, user_obj): for item in add_list: cur_disk_dict = client_disk_dict[item] log_str = '[新增硬盘]插槽为{slot};容量为{capacity};硬盘类型为{pd_type};型号为{model}'.format(**cur_disk_dict) cur_disk_dict['server_obj'] = server_obj models.Disk.objects.create(**cur_disk_dict) models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content=log_str) @staticmethod def _del_disk(del_list, disk_objs, server_obj, user_obj): for item in disk_objs: if item.slot in del_list: log_str = '[移除硬盘]插槽为{slot};容量为{capacity};硬盘类型为{pd_type};型号为{model}'.format(**item.__dict__) item.delete() models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content=log_str) @staticmethod def _update_disk(update_list, disk_objs, client_disk_dict, server_obj, user_obj): for item in disk_objs: if item.slot in update_list: log_list = [] new_model = client_disk_dict[item.slot]['model'] if item.model != new_model: log_list.append(u"[更新硬盘]插槽为%s:型号由%s变更为%s" % (item.slot, item.model, new_model)) item.model = new_model new_capacity = client_disk_dict[item.slot]['capacity'] new_capacity = float(new_capacity) if item.capacity != new_capacity: log_list.append(u"[更新硬盘]插槽为%s:容量由%s变更为%s" % (item.slot, item.capacity, new_capacity)) item.capacity = new_capacity new_pd_type = client_disk_dict[item.slot]['pd_type'] if item.pd_type != new_pd_type: log_list.append(u"[更新硬盘]插槽为%s:硬盘类型由%s变更为%s" % (item.slot, item.pd_type, new_pd_type)) item.pd_type = new_pd_type item.save() if log_list: models.AssetRecord.objects.create(asset_obj=server_obj.asset, creator=user_obj, content=';'.join(log_list))