运维平台cmdb开发-day2

一 发送数据到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']}>
get传参
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'
post传参

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执行的返回值 ...
post序列化请求

而我们客户端传送这样的数据格式的时候,用到了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模块

每一个资产信息都继承了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
        }
}'''
serialize模块

这样我就拿到了一个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('....')
post请求处理

二 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执行的返回值 ...
post序列化验证请求

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('....')
post验证请求处理

存在的问题就是,有可能这个请求被截胡,很可能会被其他人获取到这个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执行的返回值 ...
post序列化请求md5字符串验证
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"}}
        # }'
post处理加密字符串认证

第三种: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执行的返回值 ...
post序列化请求md5动态时间验证
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('....')
post处理加密时间认证

第四种:通过时间规则限制,模仿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执行的返回值 ...
psot序列化请求md5动态时间验证
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('....')
post处理加密动态时间认证

三 表结构

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)
post资产数据和数据库数据变更
#!/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))
各个资产的增删改查
原文地址:https://www.cnblogs.com/jokerbj/p/8553306.html