最近正好在给公司做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']

 六、部分展示

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

  

Python之CMDB资产管理系统的更多相关文章

  1. CMDB资产管理系统开发【day25】:需求分析

    本节内容 浅谈ITIL CMDB介绍 Django自定义用户认证 Restful 规范 资产管理功能开发 浅谈ITIL TIL即IT基础架构库(Information Technology Infra ...

  2. CMDB资产管理系统开发【day25】:表结构设计2

    表结构设计1详细注释代码 # _*_coding:utf-8_*_ __author__ = 'luoahong' from assets.myauth import UserProfile from ...

  3. CMDB资产管理系统开发【day25】:windows客户端开发

    1.目录结构 PS Y:\MadkingClient> tree /f 卷 netgame 的文件夹 PATH 列表 卷序列号为 ACE3-896E Y:. ├─bin │ NedStark.p ...

  4. CMDB资产管理系统开发【day26】:数据正式存入待存区

    1.from表单提交 1.数据提交到哪里呢? 提交到assets/new_assets_approval.html这了 2.Yes, I'm sure提交了什么?          为什么没有下拉框了 ...

  5. CMDB(资产管理系统) day1

    运维自动化最重要的就是标准化一切 自动化运维则支持以下功能: 1.OS的选择统一化,同一个项目使用同样的OS系统部署其所需要的各类软件.2.软件安装标准化,例如JAVA虚拟机,php,nginx,my ...

  6. CMDB资产管理系统开发【day25】:表结构设计1

    资产表 # _*_coding:utf-8_*_ __author__ = 'jieli' from assets.myauth import UserProfile from django.db i ...

  7. CMDB资产管理系统开发【day25】:Django 自定义用户认证

    官方文档:https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#substituting-a-custom-user-mode ...

  8. CMDB资产管理系统开发【day26】:admin action

    本节目标 审核写到数据库,我就单独写一个如下的 页面 单机go后就跳转到如下图界面,我们这节课的目标就是写一个这样的页面 asset\admin.py部分代码 注释如下: class NewAsset ...

  9. CMDB资产管理系统开发【day26】:实现资产自动更新

    1.需求分析 1.比对分析 比对的时候以那个数据源为主? old [1,2,3 ] db数据库 new [2,3,4 ] 客户端汇报过来的 当然以客户端汇报过来的数据为主 2.更新分析 不同的表到底拿 ...

随机推荐

  1. zero-shor learning 数据集

    OSR数据集下载地址: http://people.csail.mit.edu/torralba/code/spatialenvelope/ Relative Attributes Marr Priz ...

  2. 11.28JavaScript学习

    JavaScript输出JavaScript通常用于操作HTML元素,如果要访问某个HTML元素,使用document.getElementById(id)方法,使用id属性标识HTML元素 文档输出 ...

  3. Java异常的优势与缺陷,及其处理原则

    最近在做一个读取数据库元数据的框架,其中的数据库的检查异常让人印象深刻.try-catch简直让人抓狂,同时作为框架哪些异常时应该抛出来给调用人员,哪些是应该自己处理掉的,抛出来的异常时检查异常还是非 ...

  4. Git添加Gitee远程仓库

    1.使用IDEA初始化仓库,并提交代码 2.使用 git remote add origin https://gitee.com/你的码云用户名/XXXX //添加远程仓库 3.使用 git pull ...

  5. ElasticSearch报 EsThreadPoolExecutor[search, queue capacity = 1000, org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor@c0efba

    ElasticSearch报以下错误的解决办法: "type": "es_rejected_execution_exception", "reason ...

  6. 从0开始做一个的Vue图片/ 文件选择(上传)组件[基础向]

    原文:http://blog.csdn.net/sinat_17775997/article/details/58585142 之前用Vue做了一个基础的组件 vue-img-inputer ,下面就 ...

  7. Jmeter之正则

    正则转换网站:http://tool.oschina.net/regex/ 后置处理器,正则表达式提取器,写正则 待匹配文本框:放你的源文件或源代码,正则表达式:也就是你关联的那句匹配结果:根据匹配结 ...

  8. Period(sdut2476)

    [题目大意]:给定一个字符串,求到哪一位时的字串是前几位循环组成的,并求出循环次数. 思路:求每个前缀的最小循环周:从i到n枚举len,如果len%(len-next[len])==0,则这个前缀是由 ...

  9. PAT 1024 Palindromic Number[难]

    A number that will be the same when it is written forwards or backwards is known as a Palindromic Nu ...

  10. Jquery map()

    <!DOCTYPE html> <html> <head> <style>p { color:red; }</style> <scri ...