【IMU_Ops】------IV------ IMU自动化运维平台之CMDB(添加新资产)

说明
本文中所有内容仅作为学习使用,请勿用于任何商业用途。
本文为原创,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明。

  上一章节,我们仅仅是做到在admin管理后台看见我们定义的所有models信息。本章节开始主要是实现CMDB中资产新增、新资产上线、资产更新、资产展示等功能。

 #A 新增资产

  首先需要更新视图文件view.py,先不要着急去撸代码,要搞清楚新增资产的大体逻辑再去撸代码(避免返工)下图为新增资产的逻辑图示及概述:

  •   其中assets-data应该是通过POST发送至服务端的资产原始数据;
  •   资产数据通过json转换为json数据类型;
  •   进行接收到的数据进行合理检查(安全性、合理性、完整性等);
  •   判断数据是否为空,若为空则返回错误信息并退出视图;
  •   判断数据是否为字典类型(这里为了方便操作,定义资产数据为字典类型),若非字典则返回错误信息并退出视图;
  •   判断数据是否带有SN,若非则返回错误信息并退出视图(SN是标示一个合法资产的唯一字段,不能缺少不能为空);

  下面我们根据以上逻辑,编写新增资产的视图代码:

 1 from django.shortcuts import HttpResponse
 2 from django.views.decorators.csrf import csrf_exempt
 3 import json
 4 from assets import models
 5 from assets import assets_handler
 6 
 7 
 8 # Create your views here.
 9 @csrf_exempt  #这里为了方便暂且跳过Django的csrf安全机制(后期再完善安全相关配置)
10 def report(request):
11     if request.method == "POST":
12         assets_data = request.POST.get('assets_data')
13         print(assets_data)
14         data = json.loads(assets_data)
15         # 判断data是否为空
16         if not data:
17             return HttpResponse("提交的数据为空!")
18         if not issubclass(dict, type(data)):
19             return HttpResponse("提交的数据必须是字典格式!")
20         # 判断提交的数据是否有唯一键:sn
21         sn = data.get('sn', None)
22         if sn:
23             # 判断是否为线上资产中存在的资产
24             assets_obj = models.Assets.objects.filter(sn=sn)
25             if assets_obj:
26                 # 更新线上资产信息
27                 update_assets = assets_handler.UpdateAsset(request, assets_obj[0], data)
28                 return HttpResponse("资产已更新!")
29             else:
30                 # 进入待审批区域
31                 obj = assets_handler.NewAssets(request, data)
32                 response = obj.add_to_new_assets_zone()
33                 return HttpResponse(response)
34         else:
35             return HttpResponse("提交的数据中未包含SN,请校验数据!")
36     return HttpResponse("怎么就200了!")
view.py

 #B 资产数据处理

  接下来,针对assets_data进行数据处理,在view文件中我们仅仅是针对数据进行了SN的判断和数据是否为空的判断。资产更新及提交资产到待审批区域还未解决,但这里我们还有几点需要明确的:

  通过SN在已上线的资产进行查找,若存在则进入已上线资产的更新流程;

  如果没有,说明这是个新资产,需要添加到新资产区;

  创建一个assets_handler.py文件,其中新建四个类分别实现四个功能:

  NewAssets(将资源新增到待审批区域)

  ApproveAssets(审批待上线的资源)

  UpdateAssets(更新已上线资产信息)

  Log(记录资产操作日志)

  整个数据处理的大体流程为:创建一个asset_handler.NewAsset()对象,然后调用它的obj.add_to_new_assets_zone()方法,将资产数据保存至models中的NewAssetsApprovalZone中(需要在models文件新增待审批区所需要的字段,models中代码会一并整理到第二章节中),根据实际情况,接收返回相应的结果;审批待上线资产则比较粗暴,一键审批并将待上线数据直接转正即可(从待审批区域移至资产表中);更新资产则是通过view中针对SN的判断来执行相应的数据更新即可。

  新增资产分两种情况:

  1.   彻底的新资产,任何区域都不存在该资产,直接添加至待审批区域即可;
  2.   已上线资产中没有该资产,但是待审批区中存在该资产(审批人还未审批的资产),此时再次接收到相同SN的资产时,只需要更新待审批区域该资产的数据即可;

  下面是assets_handler中各个功能模块的代码:

 

NewAssets
  1 class ApproveAssets:
  2     # 审批待上线资产
  3     def __init__(self, request, assets_id):
  4         self.request = request
  5         self.new_assets = models.NewAssetApprovalZone.objects.get(id=assets_id)
  6         self.data = json.loads(self.new_assets.data)
  7 
  8     def assets_online(self):
  9         # 预留接口
 10         func = getattr(self, "_%s_online" % self.new_assets.assets_type)
 11         ret = func()
 12         return ret
 13 
 14     def _server_online(self):
 15         assets = self._create_assets()
 16         try:
 17             self._create_manufacturer(assets)  # 创建厂商
 18             self._create_server(assets)  # 创建服务器
 19             self._create_cpu(assets)  # 创建CPU
 20             self._create_ram(assets)  # 创建内存
 21             self._create_disk(assets)  # 创建硬盘
 22             self._create_nic(assets)  # 创建网卡
 23             self._delete_original_asset()  # 从待审批资产区删除已审批上线的资产
 24         except Exception as e:
 25             assets.delete()
 26             log('approve_failed', msg=e, new_assets=self.new_assets, request=self.request)
 27             print(e)
 28             return False
 29         else:
 30             # 添加日志
 31             log("online", assets=assets, request=self.request)
 32             print("新服务器上线!")
 33             return True
 34 
 35     def _create_assets(self):
 36         # 创建资产并上线
 37         assets = models.Assets.objects.create(assets_type=self.new_assets.assets_type,
 38                                               assets_name="%s:%s" % (self.new_assets.assets_type, self.new_assets.sn),
 39                                               sn=self.new_assets.sn, assets_approved=self.request.user,)
 40         return assets
 41 
 42     def _create_manufacturer(self, asset):
 43         # 创建厂商
 44         m = self.new_assets.manufacturer
 45         if m:
 46             manufacturer_obj, _ = models.ManufacturerAssets.objects.get_or_create(name=m)
 47             asset.manufacturer = manufacturer_obj
 48             asset.save()
 49 
 50     def _create_server(self, asset):
 51         # 创建服务器
 52         models.ServerAssets.objects.create(assets=asset, model=self.new_assets.model, os_type=self.new_assets.os_type,
 53                                            os_distribution=self.new_assets.os_distribution,
 54                                            os_release=self.new_assets.os_release)
 55 
 56     def _create_cpu(self, asset):
 57         # 创建CPU
 58         cpu = models.CPUAssets.objects.create(assets=asset)
 59         cpu.cpu_model = self.new_assets.cpu_model
 60         cpu.cpu_count = self.new_assets.cpu_count
 61         cpu.cpu_core_count = self.new_assets.cpu_core_count
 62         cpu.save()
 63 
 64     def _create_ram(self, asset):
 65         # 创建内存
 66         ram_list = self.data.get('ram')
 67         if not ram_list:
 68             return
 69         for ram_dict in ram_list:
 70             if not ram_dict.get('slot'):
 71                 raise ValueError("内存插槽位置不存在!")
 72             ram = models.RAMAssets()
 73             ram.assets = asset
 74             ram.slot = ram_dict.get('slot')
 75             ram.sn = ram_dict.get('sn')
 76             ram.model = ram_dict.get('model')
 77             ram.manufacturer = ram_dict.get('manufacturer')
 78             ram.volume = ram_dict.get('volume', 0)
 79             ram.save()
 80 
 81     def _create_disk(self, asset):
 82         # 创建硬盘
 83         disk_list = self.data.get('physical_disk_driver')
 84         if not disk_list:  # 一条硬盘数据都没有
 85             return
 86         for disk_dict in disk_list:
 87             if not disk_dict.get('sn'):
 88                 raise ValueError("未知sn的硬盘!")  # 根据sn确定具体某块硬盘。
 89             disk = models.DiskAssets()
 90             disk.assets = asset
 91             disk.sn = disk_dict.get('sn')
 92             disk.model = disk_dict.get('model')
 93             disk.brand = disk_dict.get('brand'),
 94             disk.slot = disk_dict.get('slot')
 95             disk.volume = disk_dict.get('volume', 0)
 96             iface = disk_dict.get('interface_type')
 97             if iface in ['SATA', 'SAS', 'SCSI', 'SSD', 'unknown']:
 98                 disk.interface_type = iface
 99 
100             disk.save()
101 
102     def _create_nic(self, asset):
103         # 创建网卡
104         nic_list = self.data.get("nic")
105         if not nic_list:
106             return
107 
108         for nic_dict in nic_list:
109             if not nic_dict.get('mac'):
110                 raise ValueError("网卡缺少mac地址!")
111             if not nic_dict.get('model'):
112                 raise ValueError("网卡型号未知!")
113 
114             nic = models.NICAssets()
115             nic.assets = asset
116             nic.name = nic_dict.get('name')
117             nic.model = nic_dict.get('model')
118             nic.mac = nic_dict.get('mac')
119             nic.ip_address = nic_dict.get('ip_address')
120             if nic_dict.get('net_mask'):
121                 if len(nic_dict.get('net_mask')) > 0:
122                     nic.net_mask = nic_dict.get('net_mask')[0]
123             nic.save()
124 
125     def _delete_original_asset(self):
126         # 对审批通过的资产进行待审批区删除(其实不删除而是通过某个字段改变状态更合理,后期再优化吧)
127         self.new_assets.delete()
ApproveAssets
  1 class UpdateAsset:
  2     # 更新已上线资产信息
  3     def __init__(self, request, assets, report_data):
  4         self.request = request
  5         self.assets = assets
  6         self.report_data = report_data
  7         self.asset_update()
  8 
  9     def asset_update(self):
 10         # 预留接口
 11         func = getattr(self, "_%s_update" % self.report_data['assets_type'])
 12         ret = func()
 13         return ret
 14 
 15     def _server_update(self):
 16         try:
 17             self._update_manufacturer()  # 更新厂商
 18             self._update_server()  # 更新服务器
 19             self._update_cpu()  # 更新CPU
 20             self._update_ram()  # 更新内存
 21             self._update_disk()  # 更新硬盘
 22             self._update_nic()  # 更新网卡
 23             self.assets.save()
 24         except Exception as e:
 25             log('update_failed', msg=e, assets=self.assets, request=self.request)
 26             print(e)
 27             return False
 28         else:
 29             # 添加日志
 30             log("update_success", assets=self.assets)
 31             print("资产数据被更新!")
 32             return True
 33 
 34     def _update_manufacturer(self):
 35         # 更新厂商
 36 
 37         m = self.report_data.get('manufacturer')
 38         if m:
 39             manufacturer_obj, _ = models.ManufacturerAssets.objects.get_or_create(name=m)
 40             self.assets.manufacturer = manufacturer_obj
 41         else:
 42             self.assets.manufacturer = None
 43         self.assets.manufacturer.save()
 44 
 45     def _update_server(self):
 46         # 更新服务器
 47         self.assets.serverassets.model = self.report_data.get('model')
 48         self.assets.serverassets.os_type = self.report_data.get('os_type')
 49         self.assets.serverassets.os_distribution = self.report_data.get('os_distribution')
 50         self.assets.serverassets.os_release = self.report_data.get('os_release')
 51         self.assets.serverassets.save()
 52 
 53     def _update_cpu(self):
 54         # 更新CPU信息
 55         self.assets.cpu_assets .cpu_model = self.report_data.get('cpu_model')
 56         self.assets.cpu_assets.cpu_count = self.report_data.get('cpu_count')
 57         self.assets.cpu_assets.cpu_core_count = self.report_data.get('cpu_core_count')
 58         self.assets.cpu_assets.save()
 59 
 60     def _update_ram(self):
 61         """
 62         更新内存信息。
 63         使用集合数据类型中差的概念,处理不同的情况。
 64         如果新数据有,但原数据没有,则新增;
 65         如果新数据没有,但原数据有,则删除原来多余的部分;
 66         如果新的和原数据都有,则更新。
 67         在原则上,下面的代码应该写成一个复用的函数,
 68         但是由于内存、硬盘、网卡在某些方面的差别,导致很难提取出重用的代码。
 69         :return:
 70         """
 71         # 获取已有内存信息,并转成字典格式
 72         old_rams = models.RAMAssets.objects.filter(assets=self.assets)
 73         old_rams_dict = dict()
 74         if old_rams:
 75             for ram in old_rams:
 76                 old_rams_dict[ram.slot] = ram
 77         # 获取新数据中的内存信息,并转成字典格式
 78         new_rams_list = self.report_data['ram']
 79         new_rams_dict = dict()
 80         if new_rams_list:
 81             for item in new_rams_list:
 82                 new_rams_dict[item['slot']] = item
 83 
 84         # 利用set类型的差集功能,获得需要删除的内存数据对象
 85         need_deleted_keys = set(old_rams_dict.keys()) - set(new_rams_dict.keys())
 86         if need_deleted_keys:
 87             for key in need_deleted_keys:
 88                 old_rams_dict[key].delete()
 89 
 90         # 需要新增或更新的
 91         if new_rams_dict:
 92             for key in new_rams_dict:
 93                 defaults = {
 94                     'sn': new_rams_dict[key].get('sn'),
 95                     'model': new_rams_dict[key].get('model'),
 96                     'brand': new_rams_dict[key].get('brand'),
 97                     'volume': new_rams_dict[key].get('volume', 0),
 98                 }
 99                 models.RAMAssets.objects.update_or_create(assets=self.assets, slot=key, defaults=defaults)
100 
101     def _update_disk(self):
102         """
103         更新硬盘信息,类似更新内存。
104         """
105         old_disks = models.DiskAssets.objects.filter(assets=self.assets)
106         old_disks_dict = dict()
107         if old_disks:
108             for disk in old_disks:
109                 old_disks_dict[disk.sn] = disk
110 
111         new_disks_list = self.report_data['physical_disk_driver']
112         new_disks_dict = dict()
113         if new_disks_list:
114             for item in new_disks_list:
115                 new_disks_dict[item['sn']] = item
116 
117         # 需要删除的
118         need_deleted_keys = set(old_disks_dict.keys()) - set(new_disks_dict.keys())
119         if need_deleted_keys:
120             for key in need_deleted_keys:
121                 old_disks_dict[key].delete()
122 
123         # 需要新增或更新的
124         if new_disks_dict:
125             for key in new_disks_dict:
126                 interface_type = new_disks_dict[key].get('interface_type', 'unknown')
127                 if interface_type not in ['SATA', 'SAS', 'SCSI', 'SSD', 'unknown']:
128                     interface_type = 'unknown'
129                 defaults = {
130                     'slot': new_disks_dict[key].get('slot'),
131                     'model': new_disks_dict[key].get('model'),
132                     'brand': new_disks_dict[key].get('brand'),
133                     'volume': new_disks_dict[key].get('volume', 0),
134                     'interface_type': interface_type,
135                 }
136                 models.DiskAssets.objects.update_or_create(assets=self.assets, sn=key, defaults=defaults)
137 
138     def _update_nic(self):
139         """
140         更新网卡信息,类似更新内存。
141         """
142         old_nics = models.NICAssets.objects.filter(assets=self.assets)
143         old_nics_dict = dict()
144         if old_nics:
145             for nic in old_nics:
146                 old_nics_dict[nic.model + nic.mac] = nic
147 
148         new_nics_list = self.report_data['nic']
149         new_nics_dict = dict()
150         if new_nics_list:
151             for item in new_nics_list:
152                 new_nics_dict[item['model'] + item['mac']] = item
153 
154         # 需要删除的
155         need_deleted_keys = set(old_nics_dict.keys()) - set(new_nics_dict.keys())
156         if need_deleted_keys:
157             for key in need_deleted_keys:
158                 old_nics_dict[key].delete()
159 
160         # 需要新增或更新的
161         if new_nics_dict:
162             for key in new_nics_dict:
163                 if new_nics_dict[key].get('net_mask') and len(new_nics_dict[key].get('net_mask')) > 0:
164                     net_mask = new_nics_dict[key].get('net_mask')[0]
165                 else:
166                     net_mask = ""
167                 defaults = {
168                     'name': new_nics_dict[key].get('name'),
169                     'ip_address': new_nics_dict[key].get('ip_address'),
170                     'net_mask': net_mask,
171                 }
172                 models.NICAssets.objects.update_or_create(assets=self.assets, model=new_nics_dict[key]['model'],
173                                                           mac=new_nics_dict[key]['mac'], defaults=defaults)
174 
175         print('更新成功!')
UpdateAssets
 1 def log(log_type, msg=None, assets=None, new_assets=None, request=None):
 2     # 记录日志
 3     event = models.EventLog()
 4     if log_type == "online":
 5         event.name = "%s <%s> :  上线" % (assets.assets_name, assets.sn)
 6         event.assets = assets
 7         event.detail = "资产成功上线!"
 8         event.user = request.user
 9     elif log_type == "approve_failed":
10         event.name = "%s <%s> :  审批失败" % (new_assets.assets_type, new_assets.sn)
11         event.new_assets = new_assets
12         event.detail = "审批失败!\n%s" % msg
13         event.user = request.user
14     elif log_type == "update_success":
15         event.name = "%s [%s] <%s> :  数据更新!" % (assets.assets_type, assets.assets_name, assets.sn)
16         event.assets = assets
17         event.detail = "更新成功!"
18     elif log_type == "update_failed":
19         event.name = "%s [%s] <%s> :  更新失败" % (assets.assets_type, assets.assets_name, assets.sn)
20         event.assets = assets
21         event.detail = "更新失败!\n%s" % msg
22         # 更多日志类型.....
23     event.save()
Log

 #B 资产数据处理

  最后还有几个工作需要完成,我们有个view但是还缺少url的配置,还需要一些测试数据来检测我们的各个功能是否ok。

  首先我们完成rul的配置,为保证整个项目的代码可读性及高扩展性,我们更新IMU_DevOps目录下的urls文件:

1 from django.contrib import admin
2 from django.urls import path, include
3 
4 urlpatterns = [
5     path('admin/', admin.site.urls),
6     path('assets/', include('assets.urls'))
7 ]
urls.py

嗯时间到,需要带娃去跨年,今年就写到这里吧。明年再更新!在这里祝大家新年快乐!2020各种顺!

  

    

猜你喜欢

转载自www.cnblogs.com/4geek/p/12125474.html
IMU
今日推荐