模型层
逻辑处理(自动处理)
- 采集的数据中的产品型号如果产品型号表中没有,则新建
- 采集的数据中的供应商如果网供应商表没有,则新建
- 采集的数据中的网卡设备和IP如果在网卡设备表和IP表中没有,则新建
这几个字段不允许通过接口进行,在接口层是只读
其他字段可以手动维护
模板层
from enum import unique
from ipaddress import ip_address
from django.db import models
from manufacturer.models import Manufacturer,ProductModel
from idcs.models import Idc
from cabinet.models import Cabinet
class Server(models.Model):
#ssh 登录的IP
ip = models.CharField("管理IP",max_length=15,db_index=True,unique=True,help_text="管理IP")
hostname = models.CharField("主机名",max_length=20,db_index=True,unique=True,help_text="主机名")
cpu = models.CharField("CPU",max_length=50,help_text="CPU")
mem= models.CharField("内存",max_length=32,help_text="内存")
disk= models.CharField("磁盘",max_length=200,help_text="磁盘")
os= models.CharField("操作系统",max_length=50,help_text="操作系统")
sn= models.CharField("SN",max_length=50,db_index=True,help_text="SN")
manufacturer= models.ForeignKey(Manufacturer,on_delete=models.CASCADE,verbose_name="制造商",help_text="制造商")
model_name= models.ForeignKey(ProductModel,on_delete=models.CASCADE,verbose_name="服务器型号",help_text="服务器型号")
rmt_card_ip= models.CharField("管理卡IP",max_length=15,db_index=True,help_text="管理卡IP")
idc= models.ForeignKey(Idc,on_delete=models.SET_NULL,null=True,verbose_name="所在机房",help_text="所在机房")
cabinet= models.ForeignKey(Cabinet,null=True,on_delete=models.SET_NULL,verbose_name="所在机柜",help_text="所在机柜")
cabinet_position = models.CharField("机柜位置",max_length=20,help_text="机柜位置")
uuid= models.CharField("UUID",max_length=50,db_index=True,unique=True,help_text="虚拟机唯一标识")
last_check = models.DateTimeField("检测时间",db_index=True,auto_now=True,help_text="检测时间")
remark = models.CharField("备注",max_length=200,null=True,help_text="备注")
def __str__(self):
return self.ip
class Meta():
db_table="resources_server"
ordering = ["id"]
class NetworkDevice(models.Model):
"""
网卡设备
"""
name = models.CharField("网卡设备名",max_length=20,help_text="网卡设备名")
mac_address = models.CharField("MAC地址",max_length=32,help_text="MAC地址")
host = models.ForeignKey(Server,on_delete=models.CASCADE,verbose_name="所在服务器",help_text="所在服务器")
remark = models.CharField("备注",max_length=200,null=True,help_text="备注")
def __self__(self):
return self.name
class Meta:
db_table="resources_network_device"
ordering=["id"]
class IP(models.Model):
"""
IP模型
"""
ip_addr = models.CharField("IP地址",max_length=15,db_index=True,unique=True,help_text="IP地址")
netmask = models.CharField("子网掩码",max_length=15,help_text="子网掩码")
remark = models.CharField("备注",max_length=200,null=True,help_text="备注")
device= models.ForeignKey(NetworkDevice,on_delete=models.CASCADE,verbose_name="所在网卡",help_text="所在网卡")
def __str__(self):
return self.ip_addr
class Meta:
db_table = "resources_ip"
ordering = ["id"]
视图层
from .models import Server,NetworkDevice,IP
from .serializers import ServerAutoReportSerializer,NetworkDeviceSerializer,IPSerializer,ServerSerializer
from rest_framework import viewsets,mixins
from django_filters.rest_framework import DjangoFilterBackend
#from .filters import ServerFilter
# 这个视图名称添加Auto,表示它是自动收集服务器数据,并且是自动收集,所以只支持post上传<mixins.CreateModelMixin>
# 当前示例是服务器的信息资源发生变更,则会自动变更
class ServerAutoReportViewSet(mixins.CreateModelMixin,viewsets.GenericViewSet):
"""
create:
创建一个服务器
"""
queryset = Server.objects.all()
serializer_class = ServerAutoReportSerializer
class ServerViewSet(viewsets.ReadOnlyModelViewSet):
"""
retrieve:
读取一个服务器信息
List:
列出所有服务器信息
"""
queryset = Server.objects.all()
serializer_class = ServerSerializer
# 对于网络设备都是自动处理,所以设置为只读
class NetworkDeviceViewSet(viewsets.ReadOnlyModelViewSet):
"""
retrieve:
返回指定网卡信息
List:
返回网卡列表
"""
queryset = NetworkDevice.objects.all()
serializer_class = NetworkDeviceSerializer
# 对于IP都是自动处理,所以设置为只读
class IPViewSet(viewsets.ReadOnlyModelViewSet):
"""
retrieve:
返回指定ip信息
List:
返回ip列表
"""
queryset = IP.objects.all()
serializer_class = IPSerializer
序列化
from rest_framework import serializers
from servers.models import Server,NetworkDevice,IP
from manufacturer.models import ProductModel,Manufacturer
class ServerAutoReportSerializer(serializers.Serializer):
"""
服务器同步序列化,这相当于是第一步检查,在这一步不做外键检查。
manufacturer = serializers.PrimaryKeyRelatedField(many=False,queryset=Manufacturer.objects.all())
"""
ip = serializers.IPAddressField(required=True)
hostname = serializers.CharField(required=True, max_length=20)
cpu = serializers.CharField(required=True, max_length=50)
mem = serializers.CharField(required=True, max_length=20)
disk = serializers.CharField(required=True, max_length=200)
os = serializers.CharField(required=True, max_length=50)
sn = serializers.CharField(required=True, max_length=50)
manufacturer = serializers.CharField(required=True)
model_name = serializers.CharField(required=True)
uuid = serializers.CharField(required=True, max_length=50)
#网卡和ip模型,server表中没有这个,它是一个关联对象
network = serializers.JSONField(required=True)
''''
一、先处理制造商,因为它自身没有任何关联关系,两种情况
1.它存在,只需要拿到它,返回供应商的instance
2.不存在,则需要创建,单独定义方法创建它
总之,这个validate_manufacturer方法,在返回的时候一定要有 Manufacturer实例
'''
def validate_manufacturer(self, value):
try:
return Manufacturer.objects.get(vendor_name__exact=value)
# 如果Manufacturer则创建它
except Manufacturer.DoesNotExist:
return self.create_manufacturer(value)
def create_manufacturer(self,vendor_name):
return Manufacturer.objects.create(vendor_name=vendor_name)
'''
二、服务器型号
验证完制造商后,处理服务器型号,它只能在对象(表)级别验证的时候操作。
首先拿到制造商的instacne,因为型号和制造商是多对一关系。
这个attr存储的是server的所有数据,是个键值对。manufacturer_obj = attrs['manufacturer'] 它可以得到对应制造商的instance
拿到一个制造商的对象后,需要检查有没有这个型号。如果制造商没有这个型号,则创建
如果何种情况,一定要将这个型号转换成对应型号的实例,然后返回
'''
def validate(self, attrs):
# network = attrs["network"]
# del attrs["network"] # 在处理字段的时候,处理完成要删除它,后续create保存的时候,会检查字段是否匹配
manufacturer_obj = attrs['manufacturer']
try:
# 在制造商实例对应的产品模型中查找是否有这个型号的模型
attrs['model_name'] = manufacturer_obj.productmodel_set.get(model_name__exact=attrs['model_name'])
#在供应商下面的产品型号中查找是否有这个型号。如果存在返回,不存在报异常,就会去创建。它需要提供制造商的实例。
except ProductModel.DoesNotExist:
# 如果没有就创建这个模型,包含模型名称和制造商
attrs['model_name'] = self.create_product_model(manufacturer_obj, attrs["model_name"])
return attrs
# 验证完成后,就可以创建模型
def create_product_model(self,manufacturer_obj,model_name):
return ProductModel.objects.create(model_name=model_name,vendor_name=manufacturer_obj)
'''
额外知识:
字典 pop() 方法删除字典给定键 key 及对应的值,返回值为被删除的值。key 值必须给出。 否则,返回 default 值。
site= {'name': '菜鸟教程', 'alexa': 10000, 'url': 'www.runoob.com'}
pop_obj=site.pop('name')
print pop_obj # 输出 :菜鸟教程
'''
'''
三、生成server
字段级别验证和对象(表)基表验证完成后。因为是post提交,所以是create
因为当前这张表没有network这个字段。所以插入数据到表的时候,需要先将这个字段拿出来(也从原有的字典中剔除)。 再生成服务器的instance。
注意:网卡的检查,需要先有servers的实例,才能检查。因为它和服务器的关系是n:1,是有关联关系的。
'''
def create(self,validated_data):
# pop就是删掉network,对字典的操作.返回值就是个被删除的值. 因为Server没有这个字段,所以需要剔除处理
# 移除数据库模型中不存在的属性
network= validated_data.pop("network")
# 内部调用django模型类的save()方法
server_obj = Server.objects.create(**validated_data) # 创建server 记录
#server_obj.networkdevice_set = network_queryset # 设置它当中的一个集合等于列表。做一对多的关系
# 需要先做判断,再关联。 因为网卡里有
self.check_server_network_device(server_obj,network)
return validated_data
'''
四、处理网卡
'''
def check_server_network_device(self, server_obj, network):
'''
# 当前服务器所有网卡
这个网卡设备是否存在,它需要根据服务器来进行判断。
先拿到当前服务器所有网卡,然后一条一条处理。来比对网卡设备表当中是否有当前服务器的网卡。
如果不存在,则创建。 创建的时候需要注意它必须要关联上是哪台服务器。所以必须要提供server的instance
'''
network_device_queryset = server_obj.networkdevice_set.all()
for device in network:
try:
# 检测device是否存在,如果不存在抛出异常
network_device_queryset.get(name__exact=device['name'])
except NetworkDevice.DoesNotExist:
# device不存在
self.create_network_device(server_obj, device)
def create_network_device(self, server_obj, device):
# 网卡设备当中没有ip字段,需要pop,device才能保存
ips = device.pop('ips')
# 这个device[“host”] 这个host是个外键,需要指定server的instance。
device['host'] = server_obj
# 创建设备
device_device_obj = NetworkDevice.objects.create(**device)
# 继续处理网卡对应的IP
self.check_ip(device_device_obj, ips)
return device_device_obj
'''
五、处理IP
接下来处理IP
检查IP的时候,必须要知道这个IP是在哪块网卡设备上。
检查ip是根据这个IP是在哪块网卡上。
先拿到所有网卡上的所有IP,进行匹配。如果存在不做任何操作。
如果不存在,则创建这些IP 到对应网卡上。
'''
def check_ip(self, network_device_obj, ifnets):
ip_queryset= network_device_obj.ip_set.all()
# 这个ifnet是当前所有网卡的IP
for ifnet in ifnets:
try:
# 如果不存在则创建
ip_queryset.get(ip_addr__exact=ifnet['ip_addr'])
except IP.DoesNotExist:
self.create_ip(network_device_obj, ifnet)
# 创建这些IP 到对应网卡上。
def create_ip(self, network_device_obj, ifnet):
ifnet['device'] = network_device_obj
return IP.objects.create(**ifnet)
class ServerSerializer(serializers.ModelSerializer):
"""
服务器序列化类
"""
class Meta:
model=Server
fields="__all__"
class IPSerializer(serializers.ModelSerializer):
"""
服务器同步序列化类
"""
class Meta:
model=IP
fields="__all__"
class NetworkDeviceSerializer(serializers.ModelSerializer):
"""
服务器同步序列化类
"""
class Meta:
model=NetworkDevice
fields="__all__"
路由及设置
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'idcs.apps.IdcsConfig',
'users.apps.UsersConfig',
'cabinet.apps.CabinetConfig',
'manufacturer.apps.ManufacturerConfig',
'servers.apps.ServersConfig',
]
# 导入子模块的视图
from idcs.views import IdcViewSet
from users.views import UserViewSet
from cabinet.views import CabinetViewSet
from manufacturer.views import ManufacturerViewSet,ProductModelViewSet
from servers.views import ServerAutoReportViewSet,NetworkDeviceViewSet,IPViewSet,ServerViewSet
# 注册
route = DefaultRouter()
route.register("idcs",IdcViewSet,basename="idcs")
route.register("users",UserViewSet,basename="users")
route.register("cabinet",CabinetViewSet,basename="cabinet")
route.register("manufacturer",ManufacturerViewSet,basename="manufacturer")
route.register("ProductModel",ProductModelViewSet,basename="ProductModel")
route.register("ServerAutoReport",ServerAutoReportViewSet,basename="ServerAutoReport")
route.register("NetworkDevice",NetworkDeviceViewSet,basename="NetworkDevice")
route.register("Server",ServerViewSet,basename="Server")
route.register("IP",IPViewSet,basename="IP")