1、需求分析

1、比对分析

比对的时候以那个数据源为主?

old [1,2,3 ] db数据库

new [2,3,4 ] 客户端汇报过来的

当然以客户端汇报过来的数据为主

2、更新分析

不同的表到底拿那个字段当做唯一值?

old nic {
n1 10.0.0.3 --> 192.168.3.22 #源数据里要拿那个字段去找
n2 172.168.10.2
n3 192.165.52.33
}
  1. sn:网卡没有sn ip一个客户端三个ip 都不靠谱,只有mac是唯一的地址,
  2. 拿新ip对应的mac地址去到网卡表里搜。拿出来之后,对比ip地址、name
  3. 如果改变了就更新,不同的表到底拿谁当做唯一值,所以要声明

3、伪代码:

def compile_component(table_name,
compare_fields=[ip,mac,netmask]
unique=mac,
client_date=nic_data)
for i in compare_fields:
db_field = getattr(table_name,i)
if db_field==nic_data[i]:
else:
table_name.db_field = nic_data[i]

1、很多字段,你咋知道那个变了?

  • 任何一个字段变了都要记录下来,改完了之后还要记录下来

2、有什么好的办法没?

  1. 没有什么好办法,你就必须每一个方法都一一对比,你可有N个字段,并且分布在不同的表
  2. 比对的时候以那个数据源为主

2、update_asset函数解析

    def update_asset(self):
func = getattr(self, '_update_%s' % self.clean_data['asset_type'])
create_obj = func()
#每一个表里面的数据都不一样,服务器端的字段是自己创建的,客户端没有,所以只能用客户端的比

3、_update_server函数解析

    def _update_server(self):
nic = self.__update_asset_component(data_source=self.clean_data['nic'],
fk='nic_set',
'''
fk是什么?
网卡关联asset 反向查找如何查找 a.nic_set;nic_set.select_related()网卡就出来了看到几个网卡,三个网卡
此处有截图
为什么要把'nic_set'传进去?
我通过asset反查我的网卡,内存,name就等于告诉去找那些表,
'''
update_fields=['name', 'sn', 'model', 'macaddress', 'ipaddress', 'netmask',
'bonding'], #要查找的字段
identify_field='macaddress' #唯一值
)
disk = self.__update_asset_component(data_source=self.clean_data['physical_disk_driver'],
fk='disk_set',
update_fields=['slot', 'sn', 'model', 'manufactory', 'capacity',
'iface_type'],
identify_field='slot'
)
ram = self.__update_asset_component(data_source=self.clean_data['ram'],
fk='ram_set',
update_fields=['slot', 'sn', 'model', 'capacity'],
identify_field='slot'
)
cpu = self.__update_cpu_component()
manufactory = self.__update_manufactory_component() server = self.__update_server_component()

fk是什么?

  • 网卡关联asset 反向查找如何查找 a.nic_set;nic_set.select_related()网卡就出来了看到几个网卡,三个网卡

  • 为什么要把'nic_set'传进去?
  • 我通过asset反查我的网卡,内存,name就等于告诉去找那些表

4、__update_asset_component函数解析

    def __update_asset_component(self, data_source, fk, update_fields, identify_field=None):
'''
data_source: the data source of this component from reporting data
fk: which key to use to find the connection between main Asset obj and each asset component
update_fields: what fields in DB will be compared and updated
identify_field: use this field to identify each component of an Asset , if set to None,means only use asset id to identify
'''
print(data_source, update_fields, identify_field)
try:
component_obj = getattr(self.asset_obj, fk)
#传进来的是字符串,要通过字符串反射成对象
if hasattr(component_obj, 'select_related'): # this component is reverse m2m relation with Asset model
objects_from_db = component_obj.select_related() #把数据取出来,循环数据库里面的数据
for obj in objects_from_db:
#n1 10.0.0.3 --> 192.168.3.22 源数据里要拿那个字段去找
#b.macaddress;getttr(b.'macaddress'); 8C-EC-4B-16-F9-9B
key_field_data = getattr(obj, identify_field)
# use this key_field_data to find the relative data source from reporting data
if type(data_source) is list:
for source_data_item in data_source:
#到客户端的数据 源里去找到跟服务器数据库中key_field_data对应的条目
key_field_data_from_source_data = source_data_item.get(identify_field)
if key_field_data_from_source_data:
if key_field_data == key_field_data_from_source_data: # find the matched source data for this component,then should compare each field in this component to see if there's any changes since last update
self.__compare_componet(model_obj=obj, fields_from_db=update_fields,
data_source=source_data_item)
'''
拿着8C-EC-4B-16-F9-9B去客户端里找,如果找到就是一样的,循环是的是三个,
拿着db的网卡,去客户端里循环,如果找不到要循环三次,
第一没获取,不是这块网卡,
循环第二次找到了,进行对比,就是这块网卡
如果第二次循环找到,就不要往下摘了,如果我循环了三次还找不到就没,删除了,
''' break #已经根据identify_field找到客户端中对应的数据条目,且对比完了,后面的loop没必要继续了
else: # key field data from source data cannot be none
self.response_msg('warning', 'AssetUpdateWarning',
"Asset component [%s]'s key field [%s] is not provided in reporting data " % (
fk, identify_field)) else: # couldn't find any matches, the asset component must be broken or changed manually
print(
'\033[33;1mError:cannot find any matches in source data by using key field val [%s],component data is missing in reporting data!\033[0m' % (
key_field_data))
self.response_msg("error", "AssetUpdateWarning",
"Cannot find any matches in source data by using key field val [%s],component data is missing in reporting data!" % (
key_field_data))

5、传进来的是字符串,要通过字符串反射成对象

6、删除一张网卡验证一下上面的函数

后台页面

报错代码如下比对一下

self.response_msg("error", "AssetUpdateWarning",
"Cannot find any matches in source data by using key field val [%s],component data is missing in reporting data!" % (
key_field_data))

服务器端控制台(整个比对过程很清晰了)

  1. 拿着db的网卡,去客户端里循环,如果找不到要循环三次,
  2. 第一没获取,不是这块网卡,
  3. 循环第二次找到了,进行对比,就是这块网卡
  4. 如果第二次循环找到,就不要往下摘了,如果我循环了三次还找不到就没,删除了,

7、__compare_component函数刨析

源代码

    def __compare_component(self, model_obj, fields_from_db, data_source):
print('---going to compare:[%s]' % model_obj, fields_from_db)
print('---source data:', data_source)
for field in fields_from_db:
val_from_db = getattr(model_obj, field) #获取到客户端的数据
val_from_data_source = data_source.get(field) #获取到数据库里的数据
if val_from_data_source:
# if type(val_from_db) is unicode:val_from_data_source = unicode(val_from_data_source)#no unicode in py3
# if type(val_from_db) in (int,long):val_from_data_source = int(val_from_data_source) #no long in py3
if type(val_from_db) in (int,):
val_from_data_source = int(val_from_data_source)
#如果数据库里的数据类型是int,就会把客户端的数据转换过成int
elif type(val_from_db) is float:
val_from_data_source = float(val_from_data_source)
elif type(val_from_db) is str:
val_from_data_source = str(val_from_data_source).strip()
if val_from_db == val_from_data_source: # this field haven't changed since last update
pass
# print '\033[32;1m val_from_db[%s] == val_from_data_source[%s]\033[0m' %(val_from_db,val_from_data_source)
else:
print('\033[34;1m val_from_db[%s] != val_from_data_source[%s]\033[0m' % (
val_from_db, val_from_data_source), type(val_from_db), type(val_from_data_source), field)
db_field = model_obj._meta.get_field(field)
db_field.save_form_data(model_obj, val_from_data_source)
model_obj.update_date = timezone.now()
model_obj.save()
log_msg = "Asset[%s] --> component[%s] --> field[%s] has changed from [%s] to [%s]" % (
self.asset_obj, model_obj, field, val_from_db, val_from_data_source)#记录日志
self.response_msg('info', 'FieldChanged', log_msg) #返回给客户端的日志
log_handler(self.asset_obj, 'FieldChanged', self.request.user, log_msg, model_obj) #真正要记录的日志
else:
self.response_msg('warning', 'AssetUpdateWarning',
"Asset component [%s]'s field [%s] is not provided in reporting data " % (
model_obj, field)) model_obj.save()

cpu数据类型设计

虽然是int,但是是字符串形式的,我为了确保不出问题,数据格式按照数据库里的字段来

获取到数据库里的数据 就会把客户端的数据转换成int

 if val_from_data_source:
# if type(val_from_db) is unicode:val_from_data_source = unicode(val_from_data_source)#no unicode in py3
# if type(val_from_db) in (int,long):val_from_data_source = int(val_from_data_source) #no long in py3
if type(val_from_db) in (int,):
val_from_data_source = int(val_from_data_source)
#如果数据库里的数据类型是int,就会把客户端的数据转换过成int

之前的写法:

if type(val_from_db) is unicode:val_from_data_source = unicode(val_from_data_source)#no unicode in py3
if type(val_from_db) in (int,long):val_from_data_source = int(val_from_data_source) #no long in py3

记录日志

日志文件里的日志

8、如何赋一个新值

admin.py后台配置代码

admin.site.register(models.Asset,AssetAdmin)
admin.site.register(models.Server)
admin.site.register(models.NetworkDevice)
admin.site.register(models.IDC)
admin.site.register(models.BusinessUnit)
admin.site.register(models.Contract)
admin.site.register(models.CPU)
admin.site.register(models.Disk)
admin.site.register(models.NIC,NicAdmin)
admin.site.register(models.RAM)
admin.site.register(models.Manufactory)
admin.site.register(models.Tag)
admin.site.register(models.Software)
admin.site.register(models.EventLog,EventLogAdmin)
admin.site.register(models.NewAssetApprovalZone,NewAssetApprovalZoneAdmin)

最简单的方法(同学们的智慧)

  

  

alex的方法

代码

    db_field = model_obj._meta.get_field(field)
db_field.save_form_data(model_obj, val_from_data_source)

客户端截图和后台截图

  

9、__filter_add_or_deleted_components函数刨析

源代码

    def __filter_add_or_deleted_components(self, model_obj_name, data_from_db, data_source, identify_field):
'''This function is filter out all component data in db but missing in reporting data, and all the data in reporting data but not in DB'''
print(data_from_db, data_source, identify_field)
data_source_key_list = [] # save all the identified keys from client data,e.g: [macaddress1,macaddress2]
if type(data_source) is list:
for data in data_source:
data_source_key_list.append(data.get(identify_field)) elif type(data_source) is dict: #dprecated
for key, data in data_source.items():
if data.get(identify_field):
data_source_key_list.append(data.get(identify_field))
else: # workround for some component uses key as identified field e.g: ram
data_source_key_list.append(key)
print('-->identify field [%s] from db :', data_source_key_list) #数据库里的数据
print('-->identify[%s] from data source:', [getattr(obj, identify_field) for obj in data_from_db]) data_source_key_list = set(data_source_key_list) #列表生成式
data_identify_val_from_db = set([getattr(obj, identify_field) for obj in data_from_db])
data_only_in_db = data_identify_val_from_db - data_source_key_list # delete all this from db 只在数据库存在的数据
data_only_in_data_source = data_source_key_list - data_identify_val_from_db # add into db #只在客户端里的数据
print('\033[31;1mdata_only_in_db:\033[0m', data_only_in_db)
print('\033[31;1mdata_only_in_data source:\033[0m', data_only_in_data_source)
self.__delete_components(all_components=data_from_db, delete_list=data_only_in_db, #服务器端删除
identify_field=identify_field) #以什么作为唯一值
if data_only_in_data_source:
self.__add_components(model_obj_name=model_obj_name, all_components=data_source,#服务器添加
add_list=data_only_in_data_source, identify_field=identify_field)

10、服务器端后台改IP地址 无论怎么改,它永远和客户端一直

第一步:后台更改两次皮地址如下图

第一更改:

第二次更改

11、__delete_components函数刨析

源代码:

    def __delete_components(self, all_components, delete_list, identify_field):
'''All the objects in delete list will be deleted from DB'''
deleting_obj_list = []
print('--deleting components', delete_list, identify_field)
for obj in all_components:
val = getattr(obj, identify_field)
if val in delete_list:
deleting_obj_list.append(obj) for i in deleting_obj_list:
log_msg = "Asset[%s] --> component[%s] --> is lacking from reporting source data, assume it has been removed or replaced,will also delete it from DB" % (
self.asset_obj, i)
self.response_msg('info', 'HardwareChanges', log_msg)
log_handler(self.asset_obj, 'HardwareChanges', self.request.user, log_msg, i)
i.delete()

12、__add_components函数刨析

源代码

   def __add_components(self, model_obj_name, all_components, add_list, identify_field):
model_class = getattr(models, model_obj_name)
will_be_creating_list = []
print('--add component list:', add_list)
if type(all_components) is list:
for data in all_components: #客户端的源数据
if data[identify_field] in add_list:
# print data
will_be_creating_list.append(data)
elif type(all_components) is dict: #deprecated
for k, data in all_components.items():
# workround for some components uses key as identified field ,e.g ram
if data.get(identify_field):
if data[identify_field] in add_list:
# print k,data
will_be_creating_list.append(data)
else: # if the identified field cannot be found from data set,then try to compare the dict key
if k in add_list:
data[
identify_field] = k # add this key into dict , because this dict will be used to create new component item in DB
will_be_creating_list.append(data) # creating components
try:
for component in will_be_creating_list:
data_set = {}
for field in model_class.auto_create_fields:
data_set[field] = component.get(field)
data_set['asset_id'] = self.asset_obj.id
obj = model_class(**data_set)
obj.save()
print('\033[32;1mCreated component with data:\033[0m', data_set)
log_msg = "Asset[%s] --> component[%s] has justed added a new item [%s]" % (
self.asset_obj, model_obj_name, data_set)
self.response_msg('info', 'NewComponentAdded', log_msg)
log_handler(self.asset_obj, 'NewComponentAdded', self.request.user, log_msg, model_obj_name) except Exception as e:
print("\033[31;1m %s \033[0m" % e)
log_msg = "Asset[%s] --> component[%s] has error: %s" % (self.asset_obj, model_obj_name, str(e))
self.response_msg('error', "AddingComponentException", log_msg)

添加一张网卡

客户端截图

13、__filter_add_or_deleted_components函数刨析

源代码:

    def __filter_add_or_deleted_components(self, model_obj_name, data_from_db, data_source, identify_field):
'''This function is filter out all component data in db but missing in reporting data, and all the data in reporting data but not in DB'''
print(data_from_db, data_source, identify_field)
data_source_key_list = [] # save all the identified keys from client data,e.g: [macaddress1,macaddress2]
if type(data_source) is list:
for data in data_source:
data_source_key_list.append(data.get(identify_field)) elif type(data_source) is dict: #dprecated
for key, data in data_source.items():
if data.get(identify_field):
data_source_key_list.append(data.get(identify_field))
else: # workround for some component uses key as identified field e.g: ram
data_source_key_list.append(key)
print('-->identify field [%s] from db :', data_source_key_list) #数据库里的数据
print('-->identify[%s] from data source:', [getattr(obj, identify_field) for obj in data_from_db]) data_source_key_list = set(data_source_key_list) #列表生成式
data_identify_val_from_db = set([getattr(obj, identify_field) for obj in data_from_db])
data_only_in_db = data_identify_val_from_db - data_source_key_list # delete all this from db 只在数据库存在的数据
data_only_in_data_source = data_source_key_list - data_identify_val_from_db # add into db #只在客户端里的数据
print('\033[31;1mdata_only_in_db:\033[0m', data_only_in_db)
print('\033[31;1mdata_only_in_data source:\033[0m', data_only_in_data_source)
self.__delete_components(all_components=data_from_db, delete_list=data_only_in_db, #服务器端删除
identify_field=identify_field) #以什么作为唯一值
if data_only_in_data_source:
self.__add_components(model_obj_name=model_obj_name, all_components=data_source,#服务器添加
add_list=data_only_in_data_source, identify_field=identify_field)

以数据库为主去找的思路,但是客户端加一块,服务器端就不知道

是因为你那着数据库里的两个网卡,去客户端里去匹配

总结:上面的方法肯定解决不了问题,就要想别的方法处理

数据库和客户端交集并集比对

创建资产组件以什么字段为准

1、不能以客户端为主,因为客户端,要是被篡改了,传过来500个字段

2、自动创建字段要提前定义好,代码看表结构

  硬盘:auto_create_fields = ['sn', 'slot', 'model', 'capacity']
网卡:auto_create_fields = ['name', 'sn', 'model', 'macaddress', 'ipaddress', 'netmask', 'bonding']
内存:auto_create_fields = ['sn', 'slot', 'manufactory', 'model', 'capacity', 'iface_type']

14、任意改内存 网卡硬盘数据(对自动更新的整体测试)

服务端给客户端返回资产id,但是客户端解析不出来,所以一直往待审批里面汇报

成功客户端截图如下

  

修改成功后台截图

     

 

CMDB资产管理系统开发【day26】:实现资产自动更新的更多相关文章

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

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

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

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

  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资产管理系统开发【day26】:CMDB上节回顾

    一.上节知识点回顾 服务器设计了一个表结构 开发了一个客户端 二.后台创建缓存区表 客户端连接服务器,在服务器的下面看报错信息 因为URL都没有写,所以我找不到呀 1.在MadKing\url.py ...

  6. CMDB资产管理系统开发【day26】:02-数据写入待存区

    一.资产自动回报数据及个更新流程图 二.表结构注释(NewAssetApprovalZone) class NewAssetApprovalZone(models.Model): "&quo ...

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

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

  8. CMDB资产管理系统开发【day26】:批准资产入库

    刚才都是一条像内存,硬盘,网卡.多条的话如何操作 只有一条数据 下面的是有多条数据的 硬盘必须字段的验证 def __create_disk_component(self): disk_info = ...

  9. CMDB资产管理系统开发【day26】:linux客户端开发

    客户端疑难点及获取流程 1.linux客户端支持2就可以,python3就是很麻烦 难道你要求所有的客户端都上pytho3吗? 现在从bin的入口进去 HouseStark.ArgvHandler(s ...

随机推荐

  1. c/c++ 继承与多态 友元与继承

    问题1:类B是类A的友元类,类C是类B的友元类,那么类C是类A的友元类吗?函数fun是类B的友元函数,那么fun是类A的友元函数吗? 都不是,友元关系不能传递. 问题2:类B是类A的友元类,类C是类B ...

  2. SQLServer无法删除登录名'***',因为该用户当前正处于登录状态解决方法

    问题描述: sqlserver在删除登录名的时候提示删除失败 标题: Microsoft SQL Server Management Studio -------------------------- ...

  3. A Deep Learning-Based System for Vulnerability Detection

    本篇文献作者提出了一种基于深度学习来检测软件漏洞的方案.       摘要:作者开始基于深度学习的漏洞检测研究,是为了减轻专家手工定义特性的繁琐任务,需要制定一些指导性原则来适用于深度学习去进行漏洞探 ...

  4. Docker:测试环境的准备-建立一台centos测试机

    一.安装虚拟机并配置网络,下面演示在一台工作机上搭建环境 基础准备: 安装VMware-workstation-full-15.0.0-10134415.exe 安装虚拟机,镜像文件:CentOS-7 ...

  5. git冲突解决办法合集

    一 换行符CRLF错误解决办法 1 错误产生原因 不同的操作系统使用的换行符是不一样的. unix/linux使用的是LF,max后期也采用了LF,但在windows一直采用的CRLF(回车)换行符. ...

  6. Spring的单例模式底层实现

    http://blog.csdn.net/cs408/article/details/48982085

  7. 安装和使用 memcached

    memcached 和 Grails,第 1 部分:安装和使用 memcached 学习 memcached 命令并评估缓存性能 本文是系列文章的第 1 部分,主要介绍 memcached 和 Gra ...

  8. c++11の条件变量

    一.条件变量的引入 std::condition_variable 解决了死锁并且控制的资源的访问顺序二避免不必要的等待.当互斥操作不够用而引入的.比如,线程可能需要等待某个条件为真才能继续执行,而一 ...

  9. Dictionary实现先进先出代替Queue

    Queue删除其中一个元素比较麻烦,这是一个重码校验的类,主要处理是用Dictionary代替Queue了.目前使用下来还算稳定.代码贴出来给有缘人参考. /// <summary> // ...

  10. Vue slot插槽内容分发

    slot插槽使用 使用场景,一般父组件中又一大段模板内容需要运用到子组件上.或者更加复杂的,子组件需要运用到父组件大段模板内容,而子组件却不知道挂载的内容是什么.挂载点的内容是由父组件来决定的. Sl ...