zoukankan      html  css  js  c++  java
  • Python之CMDB资产管理系统

    最近正好在给公司做CMDB资产管理系统,现在做的也差不多了,现在回头吧思路整理下。

    CMDB介绍

    CMDB --Configuration Management Database 配置管理数据库, CMDB存储与管理企业IT架构中设备的各种配置信息,它与所有服务支持和服务交付流程都紧密相联,支持这些流程的运转、发挥配置信息的价值,同时依赖于相关流程保证数据的准确性。

    在实际的项目中,CMDB常常被认为是构建其它ITIL流程的基础而优先考虑,ITIL项目的成败与是否成功建立CMDB有非常大的关系。

    一、需求分析

    • 存储所有IT资产信息

    • 数据可手动添加

    • 硬件信息可自动收集

    • 硬件信息可自动变更

    • 可对其它系统灵活开放API

    • API接口安全认证

     

      • 资产类型:

        • 服务器(物理机/虚拟机)

        • 网络设备(路由器/交换机/AP)

        • 机房设备(机柜/UPS)

        • 软件资产(操作系统license)

      • 资产属性:

        • 品牌、型号、位置、用途、IP

        • 供应商、厂商、合同、购买日期

    二、架构设计

    功能模块

    • 资产搜集: 通过salt搜集各minion资产信息并统一汇报至CMDB

    • 资产审核: 资产首次汇报需要人工审核

    • 资产查询: 可多条件复杂查询

    • 对外API:  方便其他系统调用资产接口信息,如运维自动化平台

    • 自动变更: 资产变更更新及变更记录

    • 自动监控: (计划)

    • 告警自愈: (暂无)

     

    什么是对外API:

    对外API接口就是提供一个可以对外部系统访问的URL,如 http://api.***.com/

    外部系统可以通过GET/POST等方法来获取想要的数据。如炫踪运维自动化平台需要展示各机房有多少台主机,这时向API传递指定的参数,API即可反馈给相应的结果。

     

    什么时候自动监控:

    当cmdb有新主机上线,则自动添加zabbix监控,并根据主机类型关联相应监控模板,如web服务器则关联web监控模板;主机下线,则自动禁用zabbix监控。

     

    什么是告警自愈:

    当系统发现机器的CPU有异常的时候,需要对 CPU高负载进行故障干预和恢复,这种情况下我们怎么做?我们可以取到告警的信息,告警里会告诉我这台机器的IP地址和告警的值; 通过IP,可以从CMDB中查一下这个机器属于哪个业务,再根据业务信息可以查询到同业务下还有那些机器; 然后我们通过同业务的IP地址把其它机器的当前CPU值都查询出来,得出的平均值再去和告警的CPU值来对比; 最后判断出是否需要系统干预。如果需要修复,系统会根据告警的IP地址到CMDB中去查询相应的恢复策略,再进行处理。通过这种灵活和完整的验证处理闭环,我们就可以构建出各种可靠的自动故障恢复策略。

     三、资产收集/汇报

    采集硬件信息,一般有两种模式:主动采集,和被动采集;

    • 编写agent,客户端定时执行=>汇报给服务端API接口 (被动)
    • salt的grains采集功能主动采集(主动)
    • pupppet的report、ansible、zabbix等

    之前采用的是第一种方法,写了一个客户端脚本支持linux和windows和linux,然后每天定时汇报给服务端的API接口。agent用salt或者ansible批量推过去就可以了。

    后来因考虑到agent版本更新等维护成本高,索性改用第二种方法,用salt自定义了一个grains并分发至所有minion,granis来搜集minion的资产信息,然后调用salt-api定时搜集所有minion返回的granis信息即可。

    方法1如图 :

     方法二,如图:

    (后台通过salt-api来获取即可)

    def task_update_asset(sapi):
        '''定时更新所有salt资产信息'''
        try:
            jid = sapi.grains_item('*','sysinfo','glob')
            all_data = sapi.get_jid_data(jid)   #拉取最新资产信息
            while not all_data:
                all_data = sapi.get_jid_data(jid)
            else:
               # print all_data
                callback = []
                tag = 0
                if all_data.get('data'):
                    all_data = all_data.get('data')
                for line in all_data:
                    data =  all_data[line].values()[0]
                    if not data:
                        continue
                    start_report = report_asset.report(json.loads(data))   #开始汇报
                    callback.append({'salt_name':line,'result':start_report})
                    tag += 1
                callback.append({u'执行总数':tag})
                return json.dumps(callback)
        except Exception,e:
            print e
            return HttpResponse('The task Faild,please check!')
    

       

    采集到的数据,可以用在线json解析一下查看

     ok,这样客户端数据就拿到了,发送给Server的API接口来接收就行了。

    四、资产汇报流程

    资产汇报流程图

    以下是资产变更展示 

     

     五、表结构设计

     表结构代码如下:

    #!/usr/bin/env python
    #encoding:utf-8
    from django.db import models
    
    class Status(models.Model):
        name = models.CharField(max_length=64)
        code = models.CharField(max_length=64)
        memo = models.TextField(u'备注', null=True, blank=True)
        def __unicode__(self):
            return self.name
        class Meta:
            verbose_name_plural = "状态"
    
    class DeviceType(models.Model):
        '''设备类型'''
        name = models.CharField(max_length=128)
        code = models.CharField(max_length=64)
        memo = models.CharField(max_length=256,null=True,blank=True)
        create_at = models.DateTimeField(blank=True, auto_now_add=True)
        update_at = models.DateTimeField(blank=True, auto_now=True)
        def __unicode__(self):
            return self.name
        class Meta:
            verbose_name_plural = "设备类型"
    
    class Asset(models.Model):
        '''资产总表'''
        device_type = models.ForeignKey('DeviceType')
        device_status = models.ForeignKey('Status',default=1,null=True, blank=True)
        cabinet_num = models.CharField(u'机柜号', max_length=30, null=True, blank=True)
        cabinet_order = models.CharField(u'机柜中序号', max_length=30, null=True, blank=True)
        memo = models.TextField(u'备注', null=True, blank=True)
        create_at = models.DateTimeField(blank=True, auto_now_add=True)
        update_at = models.DateTimeField(blank=True, auto_now=True)
        idc = models.ForeignKey('IDC', verbose_name=u'IDC机房', null=True, blank=True)
        contract = models.ForeignKey('Contract', verbose_name=u'合同', null=True, blank=True)
        trade_date = models.DateField(u'购买时间',null=True, blank=True)
        expire_date = models.DateField(u'过保修期',null=True, blank=True)
        price = models.FloatField(u'价格',null=True, blank=True)
        business_unit = models.ForeignKey('BusinessUnit', verbose_name=u'属于的业务线', null=True, blank=True)
        manage_user = models.ForeignKey('UserProfile', verbose_name=u'管理员', related_name='+', null=True, blank=True)
        tag = models.ManyToManyField('Tag', null=True, blank=True)
        latest_date = models.DateField(null=True, blank=True)
        class Meta:
            verbose_name = '资产总表'
            verbose_name_plural = "资产总表"
        def __unicode__(self):
            return self.server.sn
    
    
    
    class Server_Type(models.Model):
        '''服务器类型'''
        name = models.CharField(max_length=128)
        memo = models.CharField(max_length=256,null=True,blank=True)
        def __unicode__(self):
            return self.name
        class Meta:
            verbose_name_plural = "服务器类型"
    
    class Server(models.Model):
        '''服务器信息'''
        asset = models.OneToOneField('Asset')
        sub_asset_type = models.ForeignKey('Server_Type')
        hostname = models.CharField(max_length=128, blank=True, null=True)      
        salt_name = models.CharField(max_length=128, blank=True, null=True)     
        hosted_on = models.ForeignKey('self',related_name='hosted_on_server',blank=True,null=True,verbose_name=u'宿主机') #虚拟机关联宿主机
        service_sn = models.CharField(u'快速服务编码', max_length=128, blank=True,null=True)  
        sn = models.CharField(u'SN号', max_length=64, blank=True, null=True,unique=True) 
        manufactory = models.CharField(verbose_name=u'制造商', max_length=128, null=True, blank=True)
        model = models.CharField(u'型号', max_length=128, null=True, blank=True)
        manage_ip = models.GenericIPAddressField(u'管理IP',null=True, blank=True)
        business_ip = models.GenericIPAddressField(u'业务IP',null=True, blank=True)
        os_platform = models.CharField(u'系统类型', max_length=64, null=True, blank=True)
        os_distribution = models.CharField(u'OS厂商',max_length=64,blank=True,null=True)
        os_version = models.CharField(u'系统版本', max_length=64, null=True, blank=True)
        cpu_count = models.IntegerField(null=True, blank=True)
        cpu_physical_count = models.IntegerField(null=True, blank=True)
        cpu_model = models.CharField(max_length=128, null=True, blank=True)
        create_at = models.DateTimeField(blank=True, auto_now_add=True)
        update_at = models.DateTimeField(blank=True, auto_now=True)
        class Meta:
            verbose_name = '服务器'
            verbose_name_plural = "服务器"
            index_together = ["sn", "asset"]
        def __unicode__(self):
            return '<id:%s>'%(self.id)
    
    class NetworkDevice(models.Model):
        '''网络设备'''
        asset = models.OneToOneField('Asset')
        sub_assset_type_choices = (
            (0,'路由器'),
            (1,'交换机'),
            (2,'无线AP'),
            (3,'VPN设备'),
        )
        sub_asset_type = models.SmallIntegerField(choices=sub_assset_type_choices,verbose_name="设备类型",default=0)
        management_ip = models.CharField(u'管理IP',max_length=64,blank=True,null=True)
        vlan_ip = models.GenericIPAddressField(u'VlanIP',blank=True,null=True)
        intranet_ip = models.GenericIPAddressField(u'内网IP',blank=True,null=True)
        sn = models.CharField(u'SN号',max_length=128,unique=True)
        manufactory = models.CharField(verbose_name=u'制造商',max_length=128,null=True, blank=True)
        model = models.CharField(u'型号',max_length=128,null=True, blank=True )
        port_num = models.SmallIntegerField(u'端口个数',null=True, blank=True )
        device_detail = models.TextField(u'设置详细配置',null=True, blank=True )
        class Meta:
            verbose_name = '网络设备'
            verbose_name_plural = "网络设备"
    
    class Memory(models.Model):
        slot = models.CharField(u'插槽位',max_length=32,blank=True)
        manufactory = models.CharField(u'制造商', max_length=32,null=True,blank=True)
        model = models.CharField(u'型号', max_length=64,blank=True)
        capacity =  models.FloatField(u'容量MB',blank=True)
        sn = models.CharField(max_length=256,null=True,blank=True,default='')
        memo = models.TextField(u'备注', null=True,blank=True)
        create_at = models.DateTimeField(blank=True, auto_now_add=True)
        update_at = models.DateTimeField(blank=True, auto_now=True)
        server_info = models.ForeignKey('server')
        class Meta:
            verbose_name = '内存部件'
            verbose_name_plural = "内存部件"
        def __unicode__(self):
            return '%s: %sGB '%( self.slot, self.capacity)
    
    class NIC(models.Model):
        name = models.CharField(u'网卡名称',max_length=128,blank=True)
        model =  models.CharField(u'网卡型号', max_length=128, blank=True,null=True)
        hwaddr = models.CharField(u'网卡mac地址', max_length=64)
        up = models.BooleanField(default=False, blank=True)
        netmask = models.CharField(max_length=64,blank=True)
        ipaddrs = models.CharField(u'ip地址',max_length=256,null=True) 
        memo = models.TextField(u'备注', blank=True)
        create_at = models.DateTimeField(blank=True, auto_now_add=True)
        update_at = models.DateTimeField(blank=True, auto_now=True)
        server_info = models.ForeignKey('server')
        speed = models.CharField(max_length=64,null=True,blank=True,default='') 
        class Meta:
            verbose_name = '网卡部件'
            verbose_name_plural = "网卡部件"
        def __unicode__(self):
            return u'网卡%s --> MAC:%s;IP%s;up:%s;netmask:%s' %(self.name,self.hwaddr,self.ipaddrs,self.up,self.netmask)
    
    class Disk(models.Model):
        name = models.CharField(u'磁盘名',max_length=32,blank=True,null=True)
        slot = models.CharField(u'插槽位',max_length=32,blank=True,null=True)
        sn = models.CharField(u'SN号', max_length=128, blank=True,null=True)
        model = models.CharField(u'磁盘型号', max_length=128,blank=True,null=True)
        capacity = models.FloatField(u'磁盘容量GB',blank=True,null=True)
        disk_iface_choice = (
            ('SATA', 'SATA'),
            ('SAS', 'SAS'),
            ('SCSI', 'SCSI'),
            ('SSD', 'SSD'),
        )
        pd_type = models.CharField(u'磁盘类型',choices=disk_iface_choice,max_length=64,blank=True,null=True)
        memo = models.TextField(u'备注', blank=True)
        create_at = models.DateTimeField(blank=True, auto_now_add=True)
        update_at = models.DateTimeField(blank=True, auto_now=True)
        server_info = models.ForeignKey('server')
        def __unicode__(self):
            return 'slot:%s size:%s' % (self.slot,self.capacity)
        class Meta:
            verbose_name_plural = "硬盘"
    
    class IDC(models.Model):
        region = models.CharField(u'区域',max_length=64)
        name = models.CharField(u'机房名称',max_length=32)
        floor = models.IntegerField(u'楼层',default=1)
        display = models.CharField(max_length=128) 
        memo = models.CharField(u'备注',max_length=64)
        def __unicode__(self):
            return 'region:%s idc:%s floor:%s' %(self.region,self.name,self.floor)
        class Meta:
            verbose_name = '机房'
            verbose_name_plural = "机房"
    
    class Contract(models.Model):
        sn = models.CharField(u'合同号', max_length=64,unique=True)
        name = models.CharField(u'合同名称', max_length=64 )
        cost = models.IntegerField(u'合同金额')
        start_date = models.DateTimeField(null=True, blank=True)
        end_date = models.DateTimeField(null=True, blank=True)
        license_num = models.IntegerField(u'license数量',null=True, blank=True)
        memo = models.TextField(u'备注',null=True, blank=True)
        create_at = models.DateTimeField(blank=True, auto_now_add=True)
        update_at = models.DateTimeField(blank=True, auto_now=True)
        class Meta:
            verbose_name = '合同'
            verbose_name_plural = "合同"
        def __unicode__(self):
            return self.name
    
    class BusinessUnit(models.Model):
        name = models.CharField(u'业务线', max_length=64, unique=True)
        contact = models.ForeignKey('UserProfile')
        user_group = models.ForeignKey('UserGroup', null=True, blank=True)
        memo = models.CharField(u'备注', max_length=64, blank=True)
        def __unicode__(self):
            return self.name
    
        class Meta:
            verbose_name = '业务线'
            verbose_name_plural = "业务线"
    
    class HandleLog(models.Model):
        asset_info = models.ForeignKey('Asset')
        content = models.TextField(null=True, blank=True)
        creator = models.ForeignKey('UserProfile')
        create_at = models.DateTimeField(auto_now_add=True)
        def __unicode__(self):
            return self.content
        class Meta:
            verbose_name_plural = "资产变更日志"
    
    class ErrorLog(models.Model):
        name = models.CharField(max_length=256)
    
    
    class NewAssetApprovalZone(models.Model):
        '''没有注册的资产,允许自动汇报,但是不入库。放到待批准表里临时存储'''
        sn = models.CharField(u'资产SN号',max_length=128, unique=True) #资产不能重复汇报,一个资产批准前只能汇报一次
        asset_type_choices = (
            ('server', u'服务器'),
            ('switch', u'交换机'),
            ('router', u'路由器'),
            ('firewall', u'防火墙'),
            ('wireless', u'无线AP'),
        )
        device_type = models.CharField(choices=asset_type_choices,max_length=64,blank=True,null=True)
        manufactory = models.CharField(max_length=64,blank=True,null=True) #厂商
        model = models.CharField(max_length=128,blank=True,null=True)
        ram_size = models.IntegerField(blank=True,null=True)
        cpu_model = models.CharField(max_length=128,blank=True,null=True)
        cpu_count = models.IntegerField(blank=True,null=True)
        #cpu_core_count = models.IntegerField(blank=True,null=True)     
        cpu_physical_count = models.IntegerField(blank=True,null=True)
        #os_type = models.CharField(max_length=64,blank=True,null=True)    
        os_platform = models.CharField(u'系统类型',max_length=64,blank=True,null=True)
        os_distribution = models.CharField(u'OS厂商',max_length=64,blank=True,null=True)
        #os_release = models.CharField(max_length=64,blank=True,null=True) 
        os_version = models.CharField(u'系统名称',max_length=64,blank=True,null=True)
        data = models.TextField(u'资产数据')        #这里才是真正详细的数据,批准后存入正式表里面
        date = models.DateTimeField(u'汇报日期',auto_now_add=True)
        approved = models.BooleanField(u'已批准',default=False)
        approved_by = models.ForeignKey('UserProfile',verbose_name=u'批准人',blank=True,null=True)
        approved_date = models.DateTimeField(u'批准日期',blank=True,null=True)
    
        def __str__(self):
            return self.sn
        class Meta:
            verbose_name = '新上线待批准资产'
            verbose_name_plural = "新上线待批准资产"
            ordering = ['-id']
    

     六、部分展示

      

    未完待续。。。。。。。。。。。

      

  • 相关阅读:
    417 Pacific Atlantic Water Flow 太平洋大西洋水流
    416 Partition Equal Subset Sum 分割相同子集和
    415 Add Strings 字符串相加
    414 Third Maximum Number 第三大的数
    413 Arithmetic Slices 等差数列划分
    412 Fizz Buzz
    410 Split Array Largest Sum 分割数组的最大值
    409 Longest Palindrome 最长回文串
    day22 collection 模块 (顺便对比queue也学习了一下队列)
    day21 计算器作业
  • 原文地址:https://www.cnblogs.com/yangmv/p/6479387.html
Copyright © 2011-2022 走看看