zoukankan      html  css  js  c++  java
  • CMDB开发(三)

    6.API验证

    # 加密复习
    #1.简单的对称加密,token是固定的
    客户端请求:
    import requests
    # 1.自定义token值
    token = 'cxiong_token'
    
    # token认证都是在请求头里携带
    res = requests.get('http://127.0.0.1:8000/getInfo',
                       headers={'token': token}
                       )
    print(res.text)
    
    # 服务端修改:autoserver/views.py
    # 修改getInfo函数
    def getInfo(requests):
        # 数据获取
        if requests.method == 'POST':
            server_info = json.loads(requests.body)
            print(server_info)
            # for k,v in server_info.items():
            #     print(k,v)
            return HttpResponse('OK')
        # 服务端如何获取请求头里面的数据
        # requests.POST
    equests.FILES
    equests.GET
        # HTTP_TOKEN
        # print(requests.META)
        token = requests.META.get('HTTP_TOKEN')
        server_token ='cxiong_token'
        if token != server_token:
            return HttpResponse('token值错误')
        # 链接后台数据库获取主机名列表并返回
        return HttpResponse(['c1.com', 'c2.com'])
    
    # 2. 加盐处理:动态加盐
                一般使用当前时间结合token加密再发送
    # client请求
    # 自定义token值
    token = 'cxiong_token1'
    import time
    
    client_time = time.time()
    tmp = '%s|%s' % (token, client_time)
    print(tmp)
    # 加密
    import hashlib
    
    md5 = hashlib.md5()  # 使用md5加密
    # 传入明文数据:数据必须是bytes类型
    md5.update(tmp.encode('utf8'))
    # 生成密文数据
    res = md5.hexdigest()
    print(res)
    # 将加密的密文数据发送给服务端,也需要将加密之前的明文数据也发给服务端,让服务端通过相同的方法进行比对
    client_md5_token = '%s|%s' % (res, client_time)
    # token认证都是请求头里携带
    data = requests.get('http://127.0.0.1:8000/getInfo',
                        headers={'token': client_md5_token}
                        )
    print(data.text)
    
    # 服务端处理
    token = requests.META.get('HTTP_TOKEN')
        server_token = 'cxiong_token'
        client_md5_token,client_time = token.split('|')
        print(client_md5_token,client_time)
        # 加密认证
        tmp = '%s|%s'%(server_token,client_time)
        #加密
        import hashlib
        md5 = hashlib.md5()
        md5.update(tmp.encode('utf8'))
        res = md5.hexdigest()
        print(res)
        if res != client_md5_token:
            return HttpResponse('token值错误')
    
    # 3.设置token失效时间
        client_md5_token,client_time = token.split('|')
        import time
        server_time = time.time()
        if server_time - client_time > 10:
            return HttpResponse('token超时了')
    """大部分API验证做到第三步就可以了"""
    # 4.设置token使用次数
    """
    黑客可能会在失效时间之前截取并发送请求
        思路:
            第一次来的时候先去redis中判断是否存在
            如果存在则说明token已经使用过了
            不存在则添加到redis中(并且设置保存的超时时间)
    """
    # 5. 固定token由服务端生成发到客户端再组合的方式(看业务是否重要了)

    7.后台目录规划

    # django是一款专注于开发app的框架
    """
    1.api:接收数据并处理入库(API验证)
    2.backend : 后台管理
    # 上述两个app都需要使用模型表,那么模型表写在哪个models文件
    3.repository:单独存储模型表相关代码
    """

     8.模型表设计

    """
    #{'board': {'status': 10000, 'data': {'manufacturer': 'Parallels Software International Inc.', 'model': 'Parallels Virtual Platform', 'sn': 'Parallels-1A 1B CB 3B 64 66 4B 13 86 B0 86 FF 7E 2B 20 30'}}
    
    1.设计模型表的时候字段名与收集过来的字典的key保持一致
        models.User.objects.create(name='jason',age=18)
        d = {'name':'cxiong','age':32}
        models.User.objects.create(**d) # **d将数据打散为name=jason这种模式
        为了录入数据的时候可以借助于**快速录入
    2.模型表设计及表关系判断,根据情况自己关联
    """
    如下图

    9.模型表数据录入

    1.11张表相关统计表
    2.数据库迁移命令
        makemigrations
        migrate
    3.django admin后台管理
        1.创建超级用户:createsuperuser
        2.注册模型表
    repository/admin.py
    4.手动录入数据 1.业务线表 2.服务器表
    对应表:
    # repository/models.py
    from django.db import models
    
    
    class UserProfile(models.Model):
        """
        用户信息
        python2  字符串前面需要加u: u姓名
        """
        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)
        password = models.CharField(u'密码', max_length=64)
    
        # 规定django-admin后台管理显示的中文表
        class Meta:
            verbose_name_plural = "用户表"
    
        def __str__(self):
            return self.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 Server(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')
    
        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 Disk(models.Model):
        """
        硬盘信息
        """
        slot = models.CharField('插槽位', max_length=8)
        model = models.CharField('磁盘型号', max_length=32)
        capacity = models.CharField('磁盘容量GB', max_length=32)
        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('Server', 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('Server', 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
    
    # 注册:repository/admin.py
    # 注册模型表
    from django.contrib import admin
    from repository import models
    # Register your models here.
    
    admin.site.register(models.Server)
    admin.site.register(models.Disk)
    admin.site.register(models.IDC)
    admin.site.register(models.NIC)
    admin.site.register(models.Tag)
    admin.site.register(models.Memory)
    admin.site.register(models.ErrorLog)
    admin.site.register(models.AssetRecord)
    admin.site.register(models.UserProfile)
    admin.site.register(models.UserGroup)
    admin.site.register(models.BusinessUnit)
    11张表

    9.视图函数

    # API/views.py中getinfo函数将获取客户端上传的数据采集并处理
    # 资产是否存在
    server_info = json.loads(requests.body)
            # 通过主机名获取老的数据对应的记录
            hostname = server_info['basic']['data']['hostname']
            # 去数据库中查询是否有该服务器信息
            old_server_info = models.Server.objects.filter(hostname=hostname).first()
            # 判断
            if not old_server_info:
                return HttpResponse("资产不存在")

    以硬盘数据为例,进行增删改查

    # 先判断status状态码是否正确
    # 对数据进行筛选入库
            # 以硬盘数据为例
            # 1.校验相应状态码
            if server_info['disk']['status'] != 10000:
                # 2.记录错误日志
                models.ErrorLog.objects.create(
                    asset_obj=old_server_info,
                    title='%s 采集硬盘数据出错了' % hostname,
                    content=server_info['disk']['data']
                )
                # 最新硬盘数据
            new_disk_info = server_info['disk']['data']
            """
            new_slot_list = [0,2]
            old_slot_list = [0,1]
            新增:new_slot_list - old_slot_list = 2
            删除:old_slot_list - new_slot_list = 1
            修改:交集
            """
            # 老的硬盘数据
            old_disk_info = models.Disk.objects.filter(server_obj=old_server_info).all()
            # 先获取新硬盘数据所有slot号
            new_slot_list = list(new_disk_info.keys())
            # 再获取旧的硬盘数据所有的slot号
            old_slot_list = [obj.slot for obj in old_disk_info]
            # 利用集合操作获取新增的数据
            add_slot_list = set(new_slot_list) - set(old_slot_list)
            if add_slot_list:
                record_list = []
                for slot in add_slot_list:
                    disk_res = new_disk_info[slot]
                    # 添加变更记录
                    tmp = '添加插槽是:{slot},磁盘类型:{pd_type},磁盘容量是:{capacity},磁盘型号:{model}'.format(**disk_res)
                    # 添加disk记录  将服务器对象直接添加到字典中,之后直接利用**打散
                    disk_res['server_obj'] = old_server_info
                    models.Disk.objects.create(**disk_res)
                    record_list.append(tmp)
                # 将变更信息添加到记录表中
                record_str = ';'.join(record_list)
                models.AssetRecord.objects.create(asset_obj=old_server_info,content=record_str)
    
            return HttpResponse('OK')
    硬盘增加插槽
    # 硬盘数据的删除
            del_slot_list = set(old_slot_list) - set(new_slot_list)
            if del_slot_list:
                # 数据的删除:slot__in多条数据
                models.Disk.objects.filter(slot__in=del_slot_list,server_obj=old_server_info).delete()
                # 记录变更
                record_str = "删除的槽位slot是:%s"%(';'.join(del_slot_list))
                models.AssetRecord.objects.create(asset_obj=old_server_info,content=record_str)
    删除硬盘槽位
    # API/views.py
            # 硬盘数据的修改
            up_slot_list = set(new_slot_list) & set(old_slot_list)
            if up_slot_list:
                record_list = []
                for slot in up_slot_list:
                    new_disk_row = new_disk_info[slot] # 新数据 字典
                    # 数据库中老数据 对象
                    old_disk_row = models.Disk.objects.filter(slot=slot,server_obj=old_server_info).first()
                    # 反射:通过字符串操作对象的属性和方法(出现字符串和对象毫不犹豫使用反射的思路)
                    for k,new_v in new_disk_row.items():
                        # 1.利用反射先从老的数据中获取数据
                        old_v = getattr(old_disk_row,k)
                        # 2.判断老的数据和新的数据是否相同
                        if new_v != old_v:
                            tmp = '槽位:%s,%s由原来的%s变成了%s'%(slot,k,old_v,new_v)
                            record_list.append(tmp)
                            # 3.更新数据:将新数据设置到老的数据对象中
                            setattr(old_disk_row,k,new_v)
                            # 4.调用对象的save方法,更新数据
                            old_disk_row.save()
                if record_list:
                    models.AssetRecord.objects.create(asset_obj=old_server_info,content=';'.join(record_list))
    
            return HttpResponse('OK')
    硬盘数据的修改

     10.前后端分离

    to B:to business  面向企业产品
    to C:to client    面向客户产品
        to C:
            前后端分离
                讲究美观和用户体验
            前端
                vue react angular.js
            # 前后端分离网站:路飞  
        to B:(CMDB)
            前后端不分离
                讲究用途和功能齐全
            前端
                bootstrap、layui
            # 前后端不分离网站:很丑的基本都是

     11.前端框架使用layui

    https://www.layui.com/demo/admin.html
    
    1.使用CDN模式
        https://www.bootcdn.cn/
    
    2.直接下载文档
            使用文档中的css和js
                layui/layui.all.js
    # <script src="/static/layui/layui.all.js"></script>
                layui/css/layui.css
    # <link rel="stylesheet" href="/static/layui/css/layui.css">

     12. Xadmin使用(后台管理)

      Django-xadmin介绍

        Django是python的重量级web框架,写得少,做得多,非常适合后端开发,它很大的一个亮点是,自带后台管理模块,但它自带的后台管理有点丑,而Xadmin是基于bootstrap开发的一套后台管理框架,界面非常美观,只需几步就可以替换自带的Django_admin
    xadmin有很多小bug,使用的时候最好心理准备,可能需要你自己修改源码
        基于bootstrap的后台管理
    vue-element-admin:最新使用的
        基于vue开发的非常酷炫的后台管理

    安装步骤:

    1.在python 2.x版本中安装方法
        pip install xadmin
    
    2.xadmin在python3.6.x时代的安装方法,需要以下插件
        pip3 install django-import-export
        pip3 install django-reversion
        pip3 install django-formtools==2.1
        pip3 install future
        pip3 install httplib2
        pip3 install six
        pip3 install django-crispy-forms
    
    bootstrap高级模板:https://wrapbootstrap.com/

    3.下载xadmin
      https://github.com/sshwsfc/xadmin
       只需要zip文件中的xadmin目录

    4.在django中的根目录下创建extra_apps(如果不存在此文件夹则创建, 然后鼠标右键extra_app 随后 mark as sources root,用来创建第三方应用
    Python Package是带init文件的,跟普通Package不同)
    创建完extra_apps,需要在settings中配置一下extra_apps。设置为可搜索的路径
    # 1.创建完extra_apps,需要在settings中配置一下extra_apps。设置为可搜索的路径
    
    import sys
    sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps')) # 把extra_apps文件夹添加到搜索目录中
    
    # 2.配置到 INSTALLED_APPS
    ## 显示中文
    LANGUAGE_CODE = 'zh-hans'
     
    # TIME_ZONE = 'UTC'
    TIME_ZONE = 'Asia/Shanghai'
    # xadmin后台界面显示中文
    LANGUAGE_CODE = 'zh-hans'
    # 新增 INSTALLED_APPS = [ 'xadmin', 'crispy_forms', # 注意crispy_forms之间是下划线隔开,不是横线 ] # 3. urls.py中把admin换成xadmin import xadmin from django.conf.urls import url from django.contrib import admin urlpatterns = [ # url('admin/', admin.site.urls), url(r'^xadmin/', xadmin.site.urls), ] # 4.迁移文件:迁移完成之后数据库会多几张xadmin_开头的表 python3 manage.py makemigrations python3 manage.py migrate """因为版本的原因,有一些报错慢慢解决""" #5.pycharm创建superuser 用户 python3 manage.py 访问:http://127.0.0.1:8000/xadmin/
    Xadmin使用
    #1.需要在后台管理app中创建adminx.py文件
    import xadmin
    from repository import models
    from xadmin import views
    
    
    class UserProfileAdmin(object):
            # 1.显示的字段名称
        list_display = ['id','name' ,'email','phone','mobile']
        
            # 2.搜索时可输入的字段内容
        search_fields = ['id', 'name', 'email', 'phone']
        
        # 3.点击id可进入详细界面进行编辑(默认的)
        list_display_links = ('id',)  
        
        # 4.可编辑的列名
        list_editable = ['name' ,'email','phone','mobile']
        # list_filter = ['name' ,'email','phone','mobile']
        
        # 5.每页显示多少条
        list_per_page = 20 
        
            #6.根据id排序 
        ordering = ('id',) 
         
        # 7.设置只读字段 
        readonly_fields = ('id',) 
        
        #8.显示本条数据的所有信息
        show_detail_fields = ['asset_name'] 
        
        
        # data_charts = {
        #     "user_count": {'title': u"用户分布", "x-field": "name", "y-field": ("id",),},
        #     # "avg_count": {'title': u"Avg Report", "x-field": "date", "y-field": ('avg_count',), "order": ('date',)}
        # }
    
    xadmin.site.register(models.UserProfile,UserProfileAdmin)
    
    # 2.是否设置书签名
    默认是开启书签的
    show_bookmarks 属性: 设置是否开启书签功能, 默认为 True
    list_bookmarks 属性: 设置默认的书签. 用户可以在列表页面添加自己的书签, 你也可以实现设定好一些书签
    
    list_bookmarks = [{
        "title": "存在邮箱",   # 书签的名称, 显示在书签菜单中
        "query": {"user_email__contains": '@'}, 过滤参数, 是标准的 queryset 过滤
        "order": ("-user_name",), # 排序参数
        "cols": ('user_name', 'user_email', 'user_mobile'),# 显示的列
        }]
    
    # 3.数据导出
    """
    如果想要导出Excel数据,需要安装xlwt。
    
    默认情况下,xadmin会提供Excel,CSV,XML,json四种格式的数据导出,可以通过设置OptionClass的list_export属性来指定使用哪些导出格式(四种格式分别用xls,csv,xml,json表示)或是将list_export设置为None来禁用数据导出功能
    """
    list_export = ('xls', 'xml', 'json')
    list_export_fields = ('id', 'name', 'title')
    
    # 4. 设置全局配置
    #如下的代码可以在任何的app中
    import xadmin
    from repository import models
    
    from xadmin import views
    # 全局修改,固定写法
    class GlobalSettings(object):
        # 修改title
        site_title = 'xxx后台管理界面'
        # 修改footer
        site_footer = 'xxx的公司'
        # 收起菜单
        menu_style = 'accordion'
        
            # 设置 models图标
        # https://v3.bootcss.com/components/
            global_search_models = [models.Disk, models.Server]
        global_models_icon = {
            # Server: "glyphicon glyphicon-tree-conifer", Pool: "fa fa-cloud"
            models.Server: "fa fa-linux", 
              models.Disk: "fa fa-cloud"
        }
    
        
    # 将title和footer信息进行注册
    xadmin.site.register(views.CommAdminView,GlobalSettings)
    
    
    # 创建xadmin的最基本管理器配置,并与view绑定
    class BaseSetting(object):
        # 开启主题功能
        enable_themes = True
        use_bootswatch = True
    
    # 将基本配置管理与view绑定
    xadmin.site.register(views.BaseAdminView,BaseSetting)
    
    #5.图表显示(不好看不用)
    data_charts = {
      "host_idc_counts": {
        'title': '机房统计',
        'x-field': "idc",
        'y-field': ("idc",),
        'option': {
            "series": {"bars": {"align": "center", "barWidth": 0.3, "show": True}},
            "xaxis": {"aggregate": "count", "mode": "categories"}
        }
    }
    xadmin使用

    13. 数据可视化

    highcharts
    echarts
    antv

  • 相关阅读:
    LRU
    c++ 在临时变量上使用const引用
    剑指 Offer 13. 机器人的运动范围
    C++之对象包含与成员函数不兼容的类型限定符
    C#獲取指定格式日期
    在ORACLE產生001,002的流水號
    ASP.NET中DataList数字分页代码
    生成條碼標的Class
    sql 将横的记录显示为竖的记录 max(case when CASE ltrim(ps.SIZE) WHEN '4.5' THEN ps.PairPerCarton END is null then null else ps.PairPerCarton end ) AS [4.5]
    为什么margin-top值不是作用域父元素
  • 原文地址:https://www.cnblogs.com/yangmeichong/p/14464762.html
Copyright © 2011-2022 走看看