mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Merge v2.5 work
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rest_framework.exceptions import APIException
|
||||
|
||||
|
||||
|
249
netbox/dcim/api/nested_serializers.py
Normal file
249
netbox/dcim/api/nested_serializers.py
Normal file
@@ -0,0 +1,249 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from dcim.constants import CONNECTION_STATUS_CHOICES
|
||||
from dcim.models import (
|
||||
Cable, ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceType, DeviceRole, FrontPort, FrontPortTemplate,
|
||||
Interface, Manufacturer, Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, RearPort, RearPortTemplate,
|
||||
Region, Site, VirtualChassis,
|
||||
)
|
||||
from utilities.api import ChoiceField, WritableNestedSerializer
|
||||
|
||||
__all__ = [
|
||||
'NestedCableSerializer',
|
||||
'NestedConsolePortSerializer',
|
||||
'NestedConsoleServerPortSerializer',
|
||||
'NestedDeviceBaySerializer',
|
||||
'NestedDeviceRoleSerializer',
|
||||
'NestedDeviceSerializer',
|
||||
'NestedDeviceTypeSerializer',
|
||||
'NestedFrontPortSerializer',
|
||||
'NestedFrontPortTemplateSerializer',
|
||||
'NestedInterfaceSerializer',
|
||||
'NestedManufacturerSerializer',
|
||||
'NestedPlatformSerializer',
|
||||
'NestedPowerOutletSerializer',
|
||||
'NestedPowerPortSerializer',
|
||||
'NestedRackGroupSerializer',
|
||||
'NestedRackRoleSerializer',
|
||||
'NestedRackSerializer',
|
||||
'NestedRearPortSerializer',
|
||||
'NestedRearPortTemplateSerializer',
|
||||
'NestedRegionSerializer',
|
||||
'NestedSiteSerializer',
|
||||
'NestedVirtualChassisSerializer',
|
||||
]
|
||||
|
||||
|
||||
#
|
||||
# Regions/sites
|
||||
#
|
||||
|
||||
class NestedRegionSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
|
||||
|
||||
class Meta:
|
||||
model = Region
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
class NestedSiteSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:site-detail')
|
||||
|
||||
class Meta:
|
||||
model = Site
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Racks
|
||||
#
|
||||
|
||||
class NestedRackGroupSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackgroup-detail')
|
||||
|
||||
class Meta:
|
||||
model = RackGroup
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
class NestedRackRoleSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail')
|
||||
|
||||
class Meta:
|
||||
model = RackRole
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
class NestedRackSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail')
|
||||
|
||||
class Meta:
|
||||
model = Rack
|
||||
fields = ['id', 'url', 'name', 'display_name']
|
||||
|
||||
|
||||
#
|
||||
# Device types
|
||||
#
|
||||
|
||||
class NestedManufacturerSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail')
|
||||
|
||||
class Meta:
|
||||
model = Manufacturer
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
class NestedDeviceTypeSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail')
|
||||
manufacturer = NestedManufacturerSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = DeviceType
|
||||
fields = ['id', 'url', 'manufacturer', 'model', 'slug']
|
||||
|
||||
|
||||
class NestedRearPortTemplateSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearporttemplate-detail')
|
||||
|
||||
class Meta:
|
||||
model = RearPortTemplate
|
||||
fields = ['id', 'url', 'name']
|
||||
|
||||
|
||||
class NestedFrontPortTemplateSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontporttemplate-detail')
|
||||
|
||||
class Meta:
|
||||
model = FrontPortTemplate
|
||||
fields = ['id', 'url', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Devices
|
||||
#
|
||||
|
||||
class NestedDeviceRoleSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail')
|
||||
|
||||
class Meta:
|
||||
model = DeviceRole
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
class NestedPlatformSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail')
|
||||
|
||||
class Meta:
|
||||
model = Platform
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
class NestedDeviceSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail')
|
||||
|
||||
class Meta:
|
||||
model = Device
|
||||
fields = ['id', 'url', 'name', 'display_name']
|
||||
|
||||
|
||||
class NestedConsoleServerPortSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail')
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ConsoleServerPort
|
||||
fields = ['id', 'url', 'device', 'name', 'cable', 'connection_status']
|
||||
|
||||
|
||||
class NestedConsolePortSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail')
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ConsolePort
|
||||
fields = ['id', 'url', 'device', 'name', 'cable', 'connection_status']
|
||||
|
||||
|
||||
class NestedPowerOutletSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail')
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = PowerOutlet
|
||||
fields = ['id', 'url', 'device', 'name', 'cable', 'connection_status']
|
||||
|
||||
|
||||
class NestedPowerPortSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail')
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = PowerPort
|
||||
fields = ['id', 'url', 'device', 'name', 'cable', 'connection_status']
|
||||
|
||||
|
||||
class NestedInterfaceSerializer(WritableNestedSerializer):
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
|
||||
connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Interface
|
||||
fields = ['id', 'url', 'device', 'name', 'cable', 'connection_status']
|
||||
|
||||
|
||||
class NestedRearPortSerializer(WritableNestedSerializer):
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail')
|
||||
|
||||
class Meta:
|
||||
model = RearPort
|
||||
fields = ['id', 'url', 'device', 'name', 'cable']
|
||||
|
||||
|
||||
class NestedFrontPortSerializer(WritableNestedSerializer):
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontport-detail')
|
||||
|
||||
class Meta:
|
||||
model = FrontPort
|
||||
fields = ['id', 'url', 'device', 'name', 'cable']
|
||||
|
||||
|
||||
class NestedDeviceBaySerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail')
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = DeviceBay
|
||||
fields = ['id', 'url', 'device', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Cables
|
||||
#
|
||||
|
||||
class NestedCableSerializer(serializers.ModelSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail')
|
||||
|
||||
class Meta:
|
||||
model = Cable
|
||||
fields = ['id', 'url', 'label']
|
||||
|
||||
|
||||
#
|
||||
# Virtual chassis
|
||||
#
|
||||
|
||||
class NestedVirtualChassisSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
|
||||
master = NestedDeviceSerializer()
|
||||
|
||||
class Meta:
|
||||
model = VirtualChassis
|
||||
fields = ['id', 'url', 'master']
|
@@ -1,43 +1,58 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rest_framework import serializers
|
||||
from rest_framework.validators import UniqueTogetherValidator
|
||||
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
|
||||
|
||||
from circuits.models import Circuit, CircuitTermination
|
||||
from dcim.constants import (
|
||||
CONNECTION_STATUS_CHOICES, DEVICE_STATUS_CHOICES, IFACE_FF_CHOICES, IFACE_MODE_CHOICES, IFACE_ORDERING_CHOICES,
|
||||
RACK_FACE_CHOICES, RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, SITE_STATUS_CHOICES, SUBDEVICE_ROLE_CHOICES,
|
||||
)
|
||||
from dcim.constants import *
|
||||
from dcim.models import (
|
||||
ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
||||
DeviceBayTemplate, DeviceType, DeviceRole, Interface, InterfaceConnection, InterfaceTemplate, Manufacturer,
|
||||
InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup,
|
||||
RackReservation, RackRole, Region, Site, VirtualChassis,
|
||||
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
||||
DeviceBayTemplate, DeviceType, DeviceRole, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
|
||||
Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack,
|
||||
RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site, VirtualChassis,
|
||||
)
|
||||
from extras.api.customfields import CustomFieldModelSerializer
|
||||
from ipam.models import IPAddress, VLAN
|
||||
from tenancy.api.serializers import NestedTenantSerializer
|
||||
from users.api.serializers import NestedUserSerializer
|
||||
from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer
|
||||
from ipam.models import VLAN
|
||||
from tenancy.api.nested_serializers import NestedTenantSerializer
|
||||
from users.api.nested_serializers import NestedUserSerializer
|
||||
from utilities.api import (
|
||||
ChoiceField, SerializedPKRelatedField, TimeZoneField, ValidatedModelSerializer,
|
||||
WritableNestedSerializer,
|
||||
ChoiceField, ContentTypeField, SerializedPKRelatedField, TimeZoneField, ValidatedModelSerializer,
|
||||
WritableNestedSerializer, get_serializer_for_model,
|
||||
)
|
||||
from virtualization.models import Cluster
|
||||
from virtualization.api.nested_serializers import NestedClusterSerializer
|
||||
from .nested_serializers import *
|
||||
|
||||
|
||||
class ConnectedEndpointSerializer(ValidatedModelSerializer):
|
||||
connected_endpoint_type = serializers.SerializerMethodField(read_only=True)
|
||||
connected_endpoint = serializers.SerializerMethodField(read_only=True)
|
||||
connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True)
|
||||
|
||||
def get_connected_endpoint_type(self, obj):
|
||||
if hasattr(obj, 'connected_endpoint') and obj.connected_endpoint is not None:
|
||||
return '{}.{}'.format(
|
||||
obj.connected_endpoint._meta.app_label,
|
||||
obj.connected_endpoint._meta.model_name
|
||||
)
|
||||
return None
|
||||
|
||||
def get_connected_endpoint(self, obj):
|
||||
"""
|
||||
Return the appropriate serializer for the type of connected object.
|
||||
"""
|
||||
if getattr(obj, 'connected_endpoint', None) is None:
|
||||
return None
|
||||
|
||||
serializer = get_serializer_for_model(obj.connected_endpoint, prefix='Nested')
|
||||
context = {'request': self.context['request']}
|
||||
data = serializer(obj.connected_endpoint, context=context).data
|
||||
|
||||
return data
|
||||
|
||||
|
||||
#
|
||||
# Regions
|
||||
# Regions/sites
|
||||
#
|
||||
|
||||
class NestedRegionSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
|
||||
|
||||
class Meta:
|
||||
model = Region
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
class RegionSerializer(serializers.ModelSerializer):
|
||||
parent = NestedRegionSerializer(required=False, allow_null=True)
|
||||
|
||||
@@ -46,10 +61,6 @@ class RegionSerializer(serializers.ModelSerializer):
|
||||
fields = ['id', 'name', 'slug', 'parent']
|
||||
|
||||
|
||||
#
|
||||
# Sites
|
||||
#
|
||||
|
||||
class SiteSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||
status = ChoiceField(choices=SITE_STATUS_CHOICES, required=False)
|
||||
region = NestedRegionSerializer(required=False, allow_null=True)
|
||||
@@ -72,16 +83,8 @@ class SiteSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||
]
|
||||
|
||||
|
||||
class NestedSiteSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:site-detail')
|
||||
|
||||
class Meta:
|
||||
model = Site
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Rack groups
|
||||
# Racks
|
||||
#
|
||||
|
||||
class RackGroupSerializer(ValidatedModelSerializer):
|
||||
@@ -92,18 +95,6 @@ class RackGroupSerializer(ValidatedModelSerializer):
|
||||
fields = ['id', 'name', 'slug', 'site']
|
||||
|
||||
|
||||
class NestedRackGroupSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackgroup-detail')
|
||||
|
||||
class Meta:
|
||||
model = RackGroup
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Rack roles
|
||||
#
|
||||
|
||||
class RackRoleSerializer(ValidatedModelSerializer):
|
||||
|
||||
class Meta:
|
||||
@@ -111,32 +102,23 @@ class RackRoleSerializer(ValidatedModelSerializer):
|
||||
fields = ['id', 'name', 'slug', 'color']
|
||||
|
||||
|
||||
class NestedRackRoleSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail')
|
||||
|
||||
class Meta:
|
||||
model = RackRole
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Racks
|
||||
#
|
||||
|
||||
class RackSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||
site = NestedSiteSerializer()
|
||||
group = NestedRackGroupSerializer(required=False, allow_null=True, default=None)
|
||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||
status = ChoiceField(choices=RACK_STATUS_CHOICES, required=False)
|
||||
role = NestedRackRoleSerializer(required=False, allow_null=True)
|
||||
type = ChoiceField(choices=RACK_TYPE_CHOICES, required=False, allow_null=True)
|
||||
width = ChoiceField(choices=RACK_WIDTH_CHOICES, required=False)
|
||||
outer_unit = ChoiceField(choices=RACK_DIMENSION_UNIT_CHOICES, required=False)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Rack
|
||||
fields = [
|
||||
'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'role', 'serial', 'type', 'width',
|
||||
'u_height', 'desc_units', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||
'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'status', 'role', 'serial',
|
||||
'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit',
|
||||
'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||
]
|
||||
# Omit the UniqueTogetherValidator that would be automatically added to validate (group, facility_id). This
|
||||
# prevents facility_id from being interpreted as a required field.
|
||||
@@ -153,31 +135,11 @@ class RackSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||
validator(data)
|
||||
|
||||
# Enforce model validation
|
||||
super(RackSerializer, self).validate(data)
|
||||
super().validate(data)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class NestedRackSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail')
|
||||
|
||||
class Meta:
|
||||
model = Rack
|
||||
fields = ['id', 'url', 'name', 'display_name']
|
||||
|
||||
|
||||
#
|
||||
# Rack units
|
||||
#
|
||||
|
||||
class NestedDeviceSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail')
|
||||
|
||||
class Meta:
|
||||
model = Device
|
||||
fields = ['id', 'url', 'name', 'display_name']
|
||||
|
||||
|
||||
class RackUnitSerializer(serializers.Serializer):
|
||||
"""
|
||||
A rack unit is an abstraction formed by the set (rack, position, face); it does not exist as a row in the database.
|
||||
@@ -188,10 +150,6 @@ class RackUnitSerializer(serializers.Serializer):
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
|
||||
|
||||
#
|
||||
# Rack reservations
|
||||
#
|
||||
|
||||
class RackReservationSerializer(ValidatedModelSerializer):
|
||||
rack = NestedRackSerializer()
|
||||
user = NestedUserSerializer()
|
||||
@@ -203,7 +161,7 @@ class RackReservationSerializer(ValidatedModelSerializer):
|
||||
|
||||
|
||||
#
|
||||
# Manufacturers
|
||||
# Device types
|
||||
#
|
||||
|
||||
class ManufacturerSerializer(ValidatedModelSerializer):
|
||||
@@ -213,21 +171,8 @@ class ManufacturerSerializer(ValidatedModelSerializer):
|
||||
fields = ['id', 'name', 'slug']
|
||||
|
||||
|
||||
class NestedManufacturerSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail')
|
||||
|
||||
class Meta:
|
||||
model = Manufacturer
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Device types
|
||||
#
|
||||
|
||||
class DeviceTypeSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||
manufacturer = NestedManufacturerSerializer()
|
||||
interface_ordering = ChoiceField(choices=IFACE_ORDERING_CHOICES, required=False)
|
||||
subdevice_role = ChoiceField(choices=SUBDEVICE_ROLE_CHOICES, required=False, allow_null=True)
|
||||
instance_count = serializers.IntegerField(source='instances.count', read_only=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
@@ -235,25 +180,11 @@ class DeviceTypeSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||
class Meta:
|
||||
model = DeviceType
|
||||
fields = [
|
||||
'id', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'interface_ordering',
|
||||
'is_console_server', 'is_pdu', 'is_network_device', 'subdevice_role', 'comments', 'tags', 'custom_fields',
|
||||
'created', 'last_updated', 'instance_count',
|
||||
'id', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role',
|
||||
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'instance_count',
|
||||
]
|
||||
|
||||
|
||||
class NestedDeviceTypeSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail')
|
||||
manufacturer = NestedManufacturerSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = DeviceType
|
||||
fields = ['id', 'url', 'manufacturer', 'model', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Console port templates
|
||||
#
|
||||
|
||||
class ConsolePortTemplateSerializer(ValidatedModelSerializer):
|
||||
device_type = NestedDeviceTypeSerializer()
|
||||
|
||||
@@ -262,10 +193,6 @@ class ConsolePortTemplateSerializer(ValidatedModelSerializer):
|
||||
fields = ['id', 'device_type', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Console server port templates
|
||||
#
|
||||
|
||||
class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer):
|
||||
device_type = NestedDeviceTypeSerializer()
|
||||
|
||||
@@ -274,10 +201,6 @@ class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer):
|
||||
fields = ['id', 'device_type', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Power port templates
|
||||
#
|
||||
|
||||
class PowerPortTemplateSerializer(ValidatedModelSerializer):
|
||||
device_type = NestedDeviceTypeSerializer()
|
||||
|
||||
@@ -286,10 +209,6 @@ class PowerPortTemplateSerializer(ValidatedModelSerializer):
|
||||
fields = ['id', 'device_type', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Power outlet templates
|
||||
#
|
||||
|
||||
class PowerOutletTemplateSerializer(ValidatedModelSerializer):
|
||||
device_type = NestedDeviceTypeSerializer()
|
||||
|
||||
@@ -298,10 +217,6 @@ class PowerOutletTemplateSerializer(ValidatedModelSerializer):
|
||||
fields = ['id', 'device_type', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Interface templates
|
||||
#
|
||||
|
||||
class InterfaceTemplateSerializer(ValidatedModelSerializer):
|
||||
device_type = NestedDeviceTypeSerializer()
|
||||
form_factor = ChoiceField(choices=IFACE_FF_CHOICES, required=False)
|
||||
@@ -311,9 +226,24 @@ class InterfaceTemplateSerializer(ValidatedModelSerializer):
|
||||
fields = ['id', 'device_type', 'name', 'form_factor', 'mgmt_only']
|
||||
|
||||
|
||||
#
|
||||
# Device bay templates
|
||||
#
|
||||
class RearPortTemplateSerializer(ValidatedModelSerializer):
|
||||
device_type = NestedDeviceTypeSerializer()
|
||||
type = ChoiceField(choices=PORT_TYPE_CHOICES)
|
||||
|
||||
class Meta:
|
||||
model = RearPortTemplate
|
||||
fields = ['id', 'device_type', 'name', 'type', 'positions']
|
||||
|
||||
|
||||
class FrontPortTemplateSerializer(ValidatedModelSerializer):
|
||||
device_type = NestedDeviceTypeSerializer()
|
||||
type = ChoiceField(choices=PORT_TYPE_CHOICES)
|
||||
rear_port = NestedRearPortTemplateSerializer()
|
||||
|
||||
class Meta:
|
||||
model = FrontPortTemplate
|
||||
fields = ['id', 'device_type', 'name', 'type', 'rear_port', 'rear_port_position']
|
||||
|
||||
|
||||
class DeviceBayTemplateSerializer(ValidatedModelSerializer):
|
||||
device_type = NestedDeviceTypeSerializer()
|
||||
@@ -324,7 +254,7 @@ class DeviceBayTemplateSerializer(ValidatedModelSerializer):
|
||||
|
||||
|
||||
#
|
||||
# Device roles
|
||||
# Devices
|
||||
#
|
||||
|
||||
class DeviceRoleSerializer(ValidatedModelSerializer):
|
||||
@@ -334,64 +264,12 @@ class DeviceRoleSerializer(ValidatedModelSerializer):
|
||||
fields = ['id', 'name', 'slug', 'color', 'vm_role']
|
||||
|
||||
|
||||
class NestedDeviceRoleSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail')
|
||||
|
||||
class Meta:
|
||||
model = DeviceRole
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Platforms
|
||||
#
|
||||
|
||||
class PlatformSerializer(ValidatedModelSerializer):
|
||||
manufacturer = NestedManufacturerSerializer(required=False, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = Platform
|
||||
fields = ['id', 'name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args', 'rpc_client']
|
||||
|
||||
|
||||
class NestedPlatformSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail')
|
||||
|
||||
class Meta:
|
||||
model = Platform
|
||||
fields = ['id', 'url', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Devices
|
||||
#
|
||||
|
||||
# Cannot import ipam.api.NestedIPAddressSerializer due to circular dependency
|
||||
class DeviceIPAddressSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:ipaddress-detail')
|
||||
|
||||
class Meta:
|
||||
model = IPAddress
|
||||
fields = ['id', 'url', 'family', 'address']
|
||||
|
||||
|
||||
# Cannot import virtualization.api.NestedClusterSerializer due to circular dependency
|
||||
class NestedClusterSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail')
|
||||
|
||||
class Meta:
|
||||
model = Cluster
|
||||
fields = ['id', 'url', 'name']
|
||||
|
||||
|
||||
# Cannot import NestedVirtualChassisSerializer due to circular dependency
|
||||
class DeviceVirtualChassisSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
|
||||
master = NestedDeviceSerializer()
|
||||
|
||||
class Meta:
|
||||
model = VirtualChassis
|
||||
fields = ['id', 'url', 'master']
|
||||
fields = ['id', 'name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args']
|
||||
|
||||
|
||||
class DeviceSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||
@@ -403,12 +281,12 @@ class DeviceSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||
rack = NestedRackSerializer(required=False, allow_null=True)
|
||||
face = ChoiceField(choices=RACK_FACE_CHOICES, required=False, allow_null=True)
|
||||
status = ChoiceField(choices=DEVICE_STATUS_CHOICES, required=False)
|
||||
primary_ip = DeviceIPAddressSerializer(read_only=True)
|
||||
primary_ip4 = DeviceIPAddressSerializer(required=False, allow_null=True)
|
||||
primary_ip6 = DeviceIPAddressSerializer(required=False, allow_null=True)
|
||||
primary_ip = NestedIPAddressSerializer(read_only=True)
|
||||
primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True)
|
||||
primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
|
||||
parent_device = serializers.SerializerMethodField()
|
||||
cluster = NestedClusterSerializer(required=False, allow_null=True)
|
||||
virtual_chassis = DeviceVirtualChassisSerializer(required=False, allow_null=True)
|
||||
virtual_chassis = NestedVirtualChassisSerializer(required=False, allow_null=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
@@ -416,8 +294,8 @@ class DeviceSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||
fields = [
|
||||
'id', 'name', 'display_name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag',
|
||||
'site', 'rack', 'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4', 'primary_ip6',
|
||||
'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'tags', 'custom_fields', 'created',
|
||||
'last_updated', 'local_context_data',
|
||||
'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'local_context_data', 'tags',
|
||||
'custom_fields', 'created', 'last_updated',
|
||||
]
|
||||
validators = []
|
||||
|
||||
@@ -430,7 +308,7 @@ class DeviceSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||
validator(data)
|
||||
|
||||
# Enforce model validation
|
||||
super(DeviceSerializer, self).validate(data)
|
||||
super().validate(data)
|
||||
|
||||
return data
|
||||
|
||||
@@ -452,203 +330,90 @@ class DeviceWithConfigContextSerializer(DeviceSerializer):
|
||||
fields = [
|
||||
'id', 'name', 'display_name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag',
|
||||
'site', 'rack', 'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4', 'primary_ip6',
|
||||
'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'tags', 'custom_fields',
|
||||
'config_context', 'created', 'last_updated', 'local_context_data',
|
||||
'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'local_context_data', 'tags',
|
||||
'custom_fields', 'config_context', 'created', 'last_updated',
|
||||
]
|
||||
|
||||
def get_config_context(self, obj):
|
||||
return obj.get_config_context()
|
||||
|
||||
|
||||
#
|
||||
# Console server ports
|
||||
#
|
||||
|
||||
class ConsoleServerPortSerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||
class ConsoleServerPortSerializer(TaggitSerializer, ConnectedEndpointSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
cable = NestedCableSerializer(read_only=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = ConsoleServerPort
|
||||
fields = ['id', 'device', 'name', 'connected_console', 'tags']
|
||||
read_only_fields = ['connected_console']
|
||||
|
||||
|
||||
class NestedConsoleServerPortSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail')
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
is_connected = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ConsoleServerPort
|
||||
fields = ['id', 'url', 'device', 'name', 'is_connected']
|
||||
|
||||
def get_is_connected(self, obj):
|
||||
return hasattr(obj, 'connected_console') and obj.connected_console is not None
|
||||
|
||||
|
||||
#
|
||||
# Console ports
|
||||
#
|
||||
|
||||
class ConsolePortSerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
cs_port = NestedConsoleServerPortSerializer(required=False, allow_null=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = ConsolePort
|
||||
fields = ['id', 'device', 'name', 'cs_port', 'connection_status', 'tags']
|
||||
|
||||
|
||||
class NestedConsolePortSerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail')
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
is_connected = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ConsolePort
|
||||
fields = ['id', 'url', 'device', 'name', 'is_connected']
|
||||
|
||||
def get_is_connected(self, obj):
|
||||
return obj.cs_port is not None
|
||||
|
||||
|
||||
#
|
||||
# Power outlets
|
||||
#
|
||||
|
||||
class PowerOutletSerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = PowerOutlet
|
||||
fields = ['id', 'device', 'name', 'connected_port', 'tags']
|
||||
read_only_fields = ['connected_port']
|
||||
|
||||
|
||||
class NestedPowerOutletSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail')
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
is_connected = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = PowerOutlet
|
||||
fields = ['id', 'url', 'device', 'name', 'is_connected']
|
||||
|
||||
def get_is_connected(self, obj):
|
||||
return hasattr(obj, 'connected_port') and obj.connected_port is not None
|
||||
|
||||
|
||||
#
|
||||
# Power ports
|
||||
#
|
||||
|
||||
class PowerPortSerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
power_outlet = NestedPowerOutletSerializer(required=False, allow_null=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = PowerPort
|
||||
fields = ['id', 'device', 'name', 'power_outlet', 'connection_status', 'tags']
|
||||
|
||||
|
||||
class NestedPowerPortSerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail')
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
is_connected = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = PowerPort
|
||||
fields = ['id', 'url', 'device', 'name', 'is_connected']
|
||||
|
||||
def get_is_connected(self, obj):
|
||||
return obj.power_outlet is not None
|
||||
|
||||
|
||||
#
|
||||
# Interfaces
|
||||
#
|
||||
|
||||
class IsConnectedMixin(object):
|
||||
"""
|
||||
Provide a method for setting is_connected on Interface serializers.
|
||||
"""
|
||||
def get_is_connected(self, obj):
|
||||
"""
|
||||
Return True if the interface has a connected interface or circuit.
|
||||
"""
|
||||
if obj.connection:
|
||||
return True
|
||||
if hasattr(obj, 'circuit_termination') and obj.circuit_termination is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class NestedInterfaceSerializer(IsConnectedMixin, WritableNestedSerializer):
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
|
||||
is_connected = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Interface
|
||||
fields = ['id', 'url', 'device', 'name', 'is_connected']
|
||||
|
||||
|
||||
class InterfaceNestedCircuitSerializer(serializers.ModelSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuit-detail')
|
||||
|
||||
class Meta:
|
||||
model = Circuit
|
||||
fields = ['id', 'url', 'cid']
|
||||
|
||||
|
||||
class InterfaceCircuitTerminationSerializer(WritableNestedSerializer):
|
||||
circuit = InterfaceNestedCircuitSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = CircuitTermination
|
||||
fields = [
|
||||
'id', 'circuit', 'term_side', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info',
|
||||
'id', 'device', 'name', 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable',
|
||||
'tags',
|
||||
]
|
||||
|
||||
|
||||
# Cannot import ipam.api.NestedVLANSerializer due to circular dependency
|
||||
class InterfaceVLANSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlan-detail')
|
||||
class ConsolePortSerializer(TaggitSerializer, ConnectedEndpointSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
cable = NestedCableSerializer(read_only=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = VLAN
|
||||
fields = ['id', 'url', 'vid', 'name', 'display_name']
|
||||
model = ConsolePort
|
||||
fields = [
|
||||
'id', 'device', 'name', 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable',
|
||||
'tags',
|
||||
]
|
||||
|
||||
|
||||
class InterfaceSerializer(TaggitSerializer, IsConnectedMixin, ValidatedModelSerializer):
|
||||
class PowerOutletSerializer(TaggitSerializer, ConnectedEndpointSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
cable = NestedCableSerializer(read_only=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = PowerOutlet
|
||||
fields = [
|
||||
'id', 'device', 'name', 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable',
|
||||
'tags',
|
||||
]
|
||||
|
||||
|
||||
class PowerPortSerializer(TaggitSerializer, ConnectedEndpointSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
cable = NestedCableSerializer(read_only=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = PowerPort
|
||||
fields = [
|
||||
'id', 'device', 'name', 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable',
|
||||
'tags',
|
||||
]
|
||||
|
||||
|
||||
class InterfaceSerializer(TaggitSerializer, ConnectedEndpointSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
form_factor = ChoiceField(choices=IFACE_FF_CHOICES, required=False)
|
||||
lag = NestedInterfaceSerializer(required=False, allow_null=True)
|
||||
is_connected = serializers.SerializerMethodField(read_only=True)
|
||||
interface_connection = serializers.SerializerMethodField(read_only=True)
|
||||
circuit_termination = InterfaceCircuitTerminationSerializer(read_only=True)
|
||||
mode = ChoiceField(choices=IFACE_MODE_CHOICES, required=False, allow_null=True)
|
||||
untagged_vlan = InterfaceVLANSerializer(required=False, allow_null=True)
|
||||
untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
|
||||
tagged_vlans = SerializedPKRelatedField(
|
||||
queryset=VLAN.objects.all(),
|
||||
serializer=InterfaceVLANSerializer,
|
||||
serializer=NestedVLANSerializer,
|
||||
required=False,
|
||||
many=True
|
||||
)
|
||||
cable = NestedCableSerializer(read_only=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Interface
|
||||
fields = [
|
||||
'id', 'device', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only', 'description',
|
||||
'is_connected', 'interface_connection', 'circuit_termination', 'mode', 'untagged_vlan', 'tagged_vlans',
|
||||
'tags',
|
||||
'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable', 'mode', 'untagged_vlan',
|
||||
'tagged_vlans', 'tags', 'count_ipaddresses',
|
||||
]
|
||||
|
||||
# TODO: This validation should be handled by Interface.clean()
|
||||
def validate(self, data):
|
||||
|
||||
# All associated VLANs be global or assigned to the parent device's site.
|
||||
@@ -666,21 +431,42 @@ class InterfaceSerializer(TaggitSerializer, IsConnectedMixin, ValidatedModelSeri
|
||||
"be global.".format(vlan)
|
||||
})
|
||||
|
||||
return super(InterfaceSerializer, self).validate(data)
|
||||
|
||||
def get_interface_connection(self, obj):
|
||||
if obj.connection:
|
||||
context = {
|
||||
'request': self.context['request'],
|
||||
'interface': obj.connected_interface,
|
||||
}
|
||||
return ContextualInterfaceConnectionSerializer(obj.connection, context=context).data
|
||||
return None
|
||||
return super().validate(data)
|
||||
|
||||
|
||||
#
|
||||
# Device bays
|
||||
#
|
||||
class RearPortSerializer(ValidatedModelSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
type = ChoiceField(choices=PORT_TYPE_CHOICES)
|
||||
cable = NestedCableSerializer(read_only=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = RearPort
|
||||
fields = ['id', 'device', 'name', 'type', 'positions', 'description', 'cable', 'tags']
|
||||
|
||||
|
||||
class FrontPortRearPortSerializer(WritableNestedSerializer):
|
||||
"""
|
||||
NestedRearPortSerializer but with parent device omitted (since front and rear ports must belong to same device)
|
||||
"""
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail')
|
||||
|
||||
class Meta:
|
||||
model = RearPort
|
||||
fields = ['id', 'url', 'name']
|
||||
|
||||
|
||||
class FrontPortSerializer(ValidatedModelSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
type = ChoiceField(choices=PORT_TYPE_CHOICES)
|
||||
rear_port = FrontPortRearPortSerializer()
|
||||
cable = NestedCableSerializer(read_only=True)
|
||||
tags = TagListSerializerField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = FrontPort
|
||||
fields = ['id', 'device', 'name', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', 'tags']
|
||||
|
||||
|
||||
class DeviceBaySerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
@@ -692,15 +478,6 @@ class DeviceBaySerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||
fields = ['id', 'device', 'name', 'installed_device', 'tags']
|
||||
|
||||
|
||||
class NestedDeviceBaySerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebay-detail')
|
||||
device = NestedDeviceSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = DeviceBay
|
||||
fields = ['id', 'url', 'device', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Inventory items
|
||||
#
|
||||
@@ -720,41 +497,76 @@ class InventoryItemSerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||
]
|
||||
|
||||
|
||||
#
|
||||
# Cables
|
||||
#
|
||||
|
||||
class CableSerializer(ValidatedModelSerializer):
|
||||
termination_a_type = ContentTypeField()
|
||||
termination_b_type = ContentTypeField()
|
||||
termination_a = serializers.SerializerMethodField(read_only=True)
|
||||
termination_b = serializers.SerializerMethodField(read_only=True)
|
||||
status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, required=False)
|
||||
length_unit = ChoiceField(choices=CABLE_LENGTH_UNIT_CHOICES, required=False)
|
||||
|
||||
class Meta:
|
||||
model = Cable
|
||||
fields = [
|
||||
'id', 'termination_a_type', 'termination_a_id', 'termination_a', 'termination_b_type', 'termination_b_id',
|
||||
'termination_b', 'type', 'status', 'label', 'color', 'length', 'length_unit',
|
||||
]
|
||||
|
||||
def _get_termination(self, obj, side):
|
||||
"""
|
||||
Serialize a nested representation of a termination.
|
||||
"""
|
||||
if side.lower() not in ['a', 'b']:
|
||||
raise ValueError("Termination side must be either A or B.")
|
||||
termination = getattr(obj, 'termination_{}'.format(side.lower()))
|
||||
if termination is None:
|
||||
return None
|
||||
serializer = get_serializer_for_model(termination, prefix='Nested')
|
||||
context = {'request': self.context['request']}
|
||||
data = serializer(termination, context=context).data
|
||||
|
||||
return data
|
||||
|
||||
def get_termination_a(self, obj):
|
||||
return self._get_termination(obj, 'a')
|
||||
|
||||
def get_termination_b(self, obj):
|
||||
return self._get_termination(obj, 'b')
|
||||
|
||||
|
||||
class TracedCableSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Used only while tracing a cable path.
|
||||
"""
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail')
|
||||
|
||||
class Meta:
|
||||
model = Cable
|
||||
fields = [
|
||||
'id', 'url', 'type', 'status', 'label', 'color', 'length', 'length_unit',
|
||||
]
|
||||
|
||||
|
||||
#
|
||||
# Interface connections
|
||||
#
|
||||
|
||||
class InterfaceConnectionSerializer(ValidatedModelSerializer):
|
||||
interface_a = NestedInterfaceSerializer()
|
||||
interface_b = NestedInterfaceSerializer()
|
||||
interface_a = serializers.SerializerMethodField()
|
||||
interface_b = NestedInterfaceSerializer(source='connected_endpoint')
|
||||
connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, required=False)
|
||||
|
||||
class Meta:
|
||||
model = InterfaceConnection
|
||||
fields = ['id', 'interface_a', 'interface_b', 'connection_status']
|
||||
model = Interface
|
||||
fields = ['interface_a', 'interface_b', 'connection_status']
|
||||
|
||||
|
||||
class NestedInterfaceConnectionSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interfaceconnection-detail')
|
||||
|
||||
class Meta:
|
||||
model = InterfaceConnection
|
||||
fields = ['id', 'url', 'connection_status']
|
||||
|
||||
|
||||
class ContextualInterfaceConnectionSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
A read-only representation of an InterfaceConnection from the perspective of either of its two connected Interfaces.
|
||||
"""
|
||||
interface = serializers.SerializerMethodField(read_only=True)
|
||||
connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = InterfaceConnection
|
||||
fields = ['id', 'interface', 'connection_status']
|
||||
|
||||
def get_interface(self, obj):
|
||||
return NestedInterfaceSerializer(self.context['interface'], context=self.context).data
|
||||
def get_interface_a(self, obj):
|
||||
context = {'request': self.context['request']}
|
||||
return NestedInterfaceSerializer(instance=obj, context=context).data
|
||||
|
||||
|
||||
#
|
||||
@@ -768,11 +580,3 @@ class VirtualChassisSerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||
class Meta:
|
||||
model = VirtualChassis
|
||||
fields = ['id', 'master', 'domain', 'tags']
|
||||
|
||||
|
||||
class NestedVirtualChassisSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
|
||||
|
||||
class Meta:
|
||||
model = VirtualChassis
|
||||
fields = ['id', 'url']
|
||||
|
@@ -1,5 +1,3 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rest_framework import routers
|
||||
|
||||
from . import views
|
||||
@@ -17,7 +15,7 @@ router = routers.DefaultRouter()
|
||||
router.APIRootView = DCIMRootView
|
||||
|
||||
# Field choices
|
||||
router.register(r'_choices', views.DCIMFieldChoicesViewSet, base_name='field-choice')
|
||||
router.register(r'_choices', views.DCIMFieldChoicesViewSet, basename='field-choice')
|
||||
|
||||
# Sites
|
||||
router.register(r'regions', views.RegionViewSet)
|
||||
@@ -39,6 +37,8 @@ router.register(r'console-server-port-templates', views.ConsoleServerPortTemplat
|
||||
router.register(r'power-port-templates', views.PowerPortTemplateViewSet)
|
||||
router.register(r'power-outlet-templates', views.PowerOutletTemplateViewSet)
|
||||
router.register(r'interface-templates', views.InterfaceTemplateViewSet)
|
||||
router.register(r'front-port-templates', views.FrontPortTemplateViewSet)
|
||||
router.register(r'rear-port-templates', views.RearPortTemplateViewSet)
|
||||
router.register(r'device-bay-templates', views.DeviceBayTemplateViewSet)
|
||||
|
||||
# Devices
|
||||
@@ -52,19 +52,24 @@ router.register(r'console-server-ports', views.ConsoleServerPortViewSet)
|
||||
router.register(r'power-ports', views.PowerPortViewSet)
|
||||
router.register(r'power-outlets', views.PowerOutletViewSet)
|
||||
router.register(r'interfaces', views.InterfaceViewSet)
|
||||
router.register(r'front-ports', views.FrontPortViewSet)
|
||||
router.register(r'rear-ports', views.RearPortViewSet)
|
||||
router.register(r'device-bays', views.DeviceBayViewSet)
|
||||
router.register(r'inventory-items', views.InventoryItemViewSet)
|
||||
|
||||
# Connections
|
||||
router.register(r'console-connections', views.ConsoleConnectionViewSet, base_name='consoleconnections')
|
||||
router.register(r'power-connections', views.PowerConnectionViewSet, base_name='powerconnections')
|
||||
router.register(r'interface-connections', views.InterfaceConnectionViewSet)
|
||||
router.register(r'console-connections', views.ConsoleConnectionViewSet, basename='consoleconnections')
|
||||
router.register(r'power-connections', views.PowerConnectionViewSet, basename='powerconnections')
|
||||
router.register(r'interface-connections', views.InterfaceConnectionViewSet, basename='interfaceconnections')
|
||||
|
||||
# Cables
|
||||
router.register(r'cables', views.CableViewSet)
|
||||
|
||||
# Virtual chassis
|
||||
router.register(r'virtual-chassis', views.VirtualChassisViewSet)
|
||||
|
||||
# Miscellaneous
|
||||
router.register(r'connected-device', views.ConnectedDeviceViewSet, base_name='connected-device')
|
||||
router.register(r'connected-device', views.ConnectedDeviceViewSet, basename='connected-device')
|
||||
|
||||
app_name = 'dcim-api'
|
||||
urlpatterns = router.urls
|
||||
|
@@ -1,8 +1,7 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import F, Q
|
||||
from django.http import HttpResponseForbidden
|
||||
from django.shortcuts import get_object_or_404
|
||||
from drf_yasg import openapi
|
||||
@@ -15,15 +14,17 @@ from rest_framework.viewsets import GenericViewSet, ViewSet
|
||||
|
||||
from dcim import filters
|
||||
from dcim.models import (
|
||||
ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
||||
DeviceBayTemplate, DeviceRole, DeviceType, Interface, InterfaceConnection, InterfaceTemplate, Manufacturer,
|
||||
InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup,
|
||||
RackReservation, RackRole, Region, Site, VirtualChassis,
|
||||
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
||||
DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
|
||||
Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack,
|
||||
RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site, VirtualChassis,
|
||||
)
|
||||
from extras.api.serializers import RenderedGraphSerializer
|
||||
from extras.api.views import CustomFieldModelViewSet
|
||||
from extras.models import Graph, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
|
||||
from utilities.api import IsAuthenticatedOrLoginNotRequired, FieldChoicesViewSet, ModelViewSet, ServiceUnavailable
|
||||
from utilities.api import (
|
||||
get_serializer_for_model, IsAuthenticatedOrLoginNotRequired, FieldChoicesViewSet, ModelViewSet, ServiceUnavailable,
|
||||
)
|
||||
from . import serializers
|
||||
from .exceptions import MissingFilterException
|
||||
|
||||
@@ -34,17 +35,51 @@ from .exceptions import MissingFilterException
|
||||
|
||||
class DCIMFieldChoicesViewSet(FieldChoicesViewSet):
|
||||
fields = (
|
||||
(Cable, ['length_unit']),
|
||||
(Device, ['face', 'status']),
|
||||
(ConsolePort, ['connection_status']),
|
||||
(Interface, ['form_factor', 'mode']),
|
||||
(InterfaceConnection, ['connection_status']),
|
||||
(Interface, ['connection_status', 'form_factor', 'mode']),
|
||||
(InterfaceTemplate, ['form_factor']),
|
||||
(PowerPort, ['connection_status']),
|
||||
(Rack, ['type', 'width']),
|
||||
(Rack, ['outer_unit', 'status', 'type', 'width']),
|
||||
(Site, ['status']),
|
||||
)
|
||||
|
||||
|
||||
# Mixins
|
||||
|
||||
class CableTraceMixin(object):
|
||||
|
||||
@action(detail=True, url_path='trace')
|
||||
def trace(self, request, pk):
|
||||
"""
|
||||
Trace a complete cable path and return each segment as a three-tuple of (termination, cable, termination).
|
||||
"""
|
||||
obj = get_object_or_404(self.queryset.model, pk=pk)
|
||||
|
||||
# Initialize the path array
|
||||
path = []
|
||||
|
||||
for near_end, cable, far_end in obj.trace():
|
||||
|
||||
# Serialize each object
|
||||
serializer_a = get_serializer_for_model(near_end, prefix='Nested')
|
||||
x = serializer_a(near_end, context={'request': request}).data
|
||||
if cable is not None:
|
||||
y = serializers.TracedCableSerializer(cable, context={'request': request}).data
|
||||
else:
|
||||
y = None
|
||||
if far_end is not None:
|
||||
serializer_b = get_serializer_for_model(far_end, prefix='Nested')
|
||||
z = serializer_b(far_end, context={'request': request}).data
|
||||
else:
|
||||
z = None
|
||||
|
||||
path.append((x, y, z))
|
||||
|
||||
return Response(path)
|
||||
|
||||
|
||||
#
|
||||
# Regions
|
||||
#
|
||||
@@ -52,7 +87,7 @@ class DCIMFieldChoicesViewSet(FieldChoicesViewSet):
|
||||
class RegionViewSet(ModelViewSet):
|
||||
queryset = Region.objects.all()
|
||||
serializer_class = serializers.RegionSerializer
|
||||
filter_class = filters.RegionFilter
|
||||
filterset_class = filters.RegionFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -62,7 +97,7 @@ class RegionViewSet(ModelViewSet):
|
||||
class SiteViewSet(CustomFieldModelViewSet):
|
||||
queryset = Site.objects.select_related('region', 'tenant').prefetch_related('tags')
|
||||
serializer_class = serializers.SiteSerializer
|
||||
filter_class = filters.SiteFilter
|
||||
filterset_class = filters.SiteFilter
|
||||
|
||||
@action(detail=True)
|
||||
def graphs(self, request, pk=None):
|
||||
@@ -82,7 +117,7 @@ class SiteViewSet(CustomFieldModelViewSet):
|
||||
class RackGroupViewSet(ModelViewSet):
|
||||
queryset = RackGroup.objects.select_related('site')
|
||||
serializer_class = serializers.RackGroupSerializer
|
||||
filter_class = filters.RackGroupFilter
|
||||
filterset_class = filters.RackGroupFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -92,7 +127,7 @@ class RackGroupViewSet(ModelViewSet):
|
||||
class RackRoleViewSet(ModelViewSet):
|
||||
queryset = RackRole.objects.all()
|
||||
serializer_class = serializers.RackRoleSerializer
|
||||
filter_class = filters.RackRoleFilter
|
||||
filterset_class = filters.RackRoleFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -102,7 +137,7 @@ class RackRoleViewSet(ModelViewSet):
|
||||
class RackViewSet(CustomFieldModelViewSet):
|
||||
queryset = Rack.objects.select_related('site', 'group__site', 'tenant').prefetch_related('tags')
|
||||
serializer_class = serializers.RackSerializer
|
||||
filter_class = filters.RackFilter
|
||||
filterset_class = filters.RackFilter
|
||||
|
||||
@action(detail=True)
|
||||
def units(self, request, pk=None):
|
||||
@@ -132,7 +167,7 @@ class RackViewSet(CustomFieldModelViewSet):
|
||||
class RackReservationViewSet(ModelViewSet):
|
||||
queryset = RackReservation.objects.select_related('rack', 'user', 'tenant')
|
||||
serializer_class = serializers.RackReservationSerializer
|
||||
filter_class = filters.RackReservationFilter
|
||||
filterset_class = filters.RackReservationFilter
|
||||
|
||||
# Assign user from request
|
||||
def perform_create(self, serializer):
|
||||
@@ -146,7 +181,7 @@ class RackReservationViewSet(ModelViewSet):
|
||||
class ManufacturerViewSet(ModelViewSet):
|
||||
queryset = Manufacturer.objects.all()
|
||||
serializer_class = serializers.ManufacturerSerializer
|
||||
filter_class = filters.ManufacturerFilter
|
||||
filterset_class = filters.ManufacturerFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -156,7 +191,7 @@ class ManufacturerViewSet(ModelViewSet):
|
||||
class DeviceTypeViewSet(CustomFieldModelViewSet):
|
||||
queryset = DeviceType.objects.select_related('manufacturer').prefetch_related('tags')
|
||||
serializer_class = serializers.DeviceTypeSerializer
|
||||
filter_class = filters.DeviceTypeFilter
|
||||
filterset_class = filters.DeviceTypeFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -166,37 +201,49 @@ class DeviceTypeViewSet(CustomFieldModelViewSet):
|
||||
class ConsolePortTemplateViewSet(ModelViewSet):
|
||||
queryset = ConsolePortTemplate.objects.select_related('device_type__manufacturer')
|
||||
serializer_class = serializers.ConsolePortTemplateSerializer
|
||||
filter_class = filters.ConsolePortTemplateFilter
|
||||
filterset_class = filters.ConsolePortTemplateFilter
|
||||
|
||||
|
||||
class ConsoleServerPortTemplateViewSet(ModelViewSet):
|
||||
queryset = ConsoleServerPortTemplate.objects.select_related('device_type__manufacturer')
|
||||
serializer_class = serializers.ConsoleServerPortTemplateSerializer
|
||||
filter_class = filters.ConsoleServerPortTemplateFilter
|
||||
filterset_class = filters.ConsoleServerPortTemplateFilter
|
||||
|
||||
|
||||
class PowerPortTemplateViewSet(ModelViewSet):
|
||||
queryset = PowerPortTemplate.objects.select_related('device_type__manufacturer')
|
||||
serializer_class = serializers.PowerPortTemplateSerializer
|
||||
filter_class = filters.PowerPortTemplateFilter
|
||||
filterset_class = filters.PowerPortTemplateFilter
|
||||
|
||||
|
||||
class PowerOutletTemplateViewSet(ModelViewSet):
|
||||
queryset = PowerOutletTemplate.objects.select_related('device_type__manufacturer')
|
||||
serializer_class = serializers.PowerOutletTemplateSerializer
|
||||
filter_class = filters.PowerOutletTemplateFilter
|
||||
filterset_class = filters.PowerOutletTemplateFilter
|
||||
|
||||
|
||||
class InterfaceTemplateViewSet(ModelViewSet):
|
||||
queryset = InterfaceTemplate.objects.select_related('device_type__manufacturer')
|
||||
serializer_class = serializers.InterfaceTemplateSerializer
|
||||
filter_class = filters.InterfaceTemplateFilter
|
||||
filterset_class = filters.InterfaceTemplateFilter
|
||||
|
||||
|
||||
class FrontPortTemplateViewSet(ModelViewSet):
|
||||
queryset = FrontPortTemplate.objects.select_related('device_type__manufacturer')
|
||||
serializer_class = serializers.FrontPortTemplateSerializer
|
||||
filterset_class = filters.FrontPortTemplateFilter
|
||||
|
||||
|
||||
class RearPortTemplateViewSet(ModelViewSet):
|
||||
queryset = RearPortTemplate.objects.select_related('device_type__manufacturer')
|
||||
serializer_class = serializers.RearPortTemplateSerializer
|
||||
filterset_class = filters.RearPortTemplateFilter
|
||||
|
||||
|
||||
class DeviceBayTemplateViewSet(ModelViewSet):
|
||||
queryset = DeviceBayTemplate.objects.select_related('device_type__manufacturer')
|
||||
serializer_class = serializers.DeviceBayTemplateSerializer
|
||||
filter_class = filters.DeviceBayTemplateFilter
|
||||
filterset_class = filters.DeviceBayTemplateFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -206,7 +253,7 @@ class DeviceBayTemplateViewSet(ModelViewSet):
|
||||
class DeviceRoleViewSet(ModelViewSet):
|
||||
queryset = DeviceRole.objects.all()
|
||||
serializer_class = serializers.DeviceRoleSerializer
|
||||
filter_class = filters.DeviceRoleFilter
|
||||
filterset_class = filters.DeviceRoleFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -216,7 +263,7 @@ class DeviceRoleViewSet(ModelViewSet):
|
||||
class PlatformViewSet(ModelViewSet):
|
||||
queryset = Platform.objects.all()
|
||||
serializer_class = serializers.PlatformSerializer
|
||||
filter_class = filters.PlatformFilter
|
||||
filterset_class = filters.PlatformFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -230,7 +277,7 @@ class DeviceViewSet(CustomFieldModelViewSet):
|
||||
).prefetch_related(
|
||||
'primary_ip4__nat_outside', 'primary_ip6__nat_outside', 'tags',
|
||||
)
|
||||
filter_class = filters.DeviceFilter
|
||||
filterset_class = filters.DeviceFilter
|
||||
|
||||
def get_serializer_class(self):
|
||||
"""
|
||||
@@ -321,34 +368,54 @@ class DeviceViewSet(CustomFieldModelViewSet):
|
||||
# Device components
|
||||
#
|
||||
|
||||
class ConsolePortViewSet(ModelViewSet):
|
||||
queryset = ConsolePort.objects.select_related('device', 'cs_port__device').prefetch_related('tags')
|
||||
class ConsolePortViewSet(CableTraceMixin, ModelViewSet):
|
||||
queryset = ConsolePort.objects.select_related(
|
||||
'device', 'connected_endpoint__device', 'cable'
|
||||
).prefetch_related(
|
||||
'tags'
|
||||
)
|
||||
serializer_class = serializers.ConsolePortSerializer
|
||||
filter_class = filters.ConsolePortFilter
|
||||
filterset_class = filters.ConsolePortFilter
|
||||
|
||||
|
||||
class ConsoleServerPortViewSet(ModelViewSet):
|
||||
queryset = ConsoleServerPort.objects.select_related('device', 'connected_console__device').prefetch_related('tags')
|
||||
class ConsoleServerPortViewSet(CableTraceMixin, ModelViewSet):
|
||||
queryset = ConsoleServerPort.objects.select_related(
|
||||
'device', 'connected_endpoint__device', 'cable'
|
||||
).prefetch_related(
|
||||
'tags'
|
||||
)
|
||||
serializer_class = serializers.ConsoleServerPortSerializer
|
||||
filter_class = filters.ConsoleServerPortFilter
|
||||
filterset_class = filters.ConsoleServerPortFilter
|
||||
|
||||
|
||||
class PowerPortViewSet(ModelViewSet):
|
||||
queryset = PowerPort.objects.select_related('device', 'power_outlet__device').prefetch_related('tags')
|
||||
class PowerPortViewSet(CableTraceMixin, ModelViewSet):
|
||||
queryset = PowerPort.objects.select_related(
|
||||
'device', 'connected_endpoint__device', 'cable'
|
||||
).prefetch_related(
|
||||
'tags'
|
||||
)
|
||||
serializer_class = serializers.PowerPortSerializer
|
||||
filter_class = filters.PowerPortFilter
|
||||
filterset_class = filters.PowerPortFilter
|
||||
|
||||
|
||||
class PowerOutletViewSet(ModelViewSet):
|
||||
queryset = PowerOutlet.objects.select_related('device', 'connected_port__device').prefetch_related('tags')
|
||||
class PowerOutletViewSet(CableTraceMixin, ModelViewSet):
|
||||
queryset = PowerOutlet.objects.select_related(
|
||||
'device', 'connected_endpoint__device', 'cable'
|
||||
).prefetch_related(
|
||||
'tags'
|
||||
)
|
||||
serializer_class = serializers.PowerOutletSerializer
|
||||
filter_class = filters.PowerOutletFilter
|
||||
filterset_class = filters.PowerOutletFilter
|
||||
|
||||
|
||||
class InterfaceViewSet(ModelViewSet):
|
||||
queryset = Interface.objects.select_related('device').prefetch_related('tags')
|
||||
class InterfaceViewSet(CableTraceMixin, ModelViewSet):
|
||||
queryset = Interface.objects.select_related(
|
||||
'device', '_connected_interface', '_connected_circuittermination', 'cable'
|
||||
).prefetch_related(
|
||||
'ip_addresses', 'tags'
|
||||
)
|
||||
serializer_class = serializers.InterfaceSerializer
|
||||
filter_class = filters.InterfaceFilter
|
||||
filterset_class = filters.InterfaceFilter
|
||||
|
||||
@action(detail=True)
|
||||
def graphs(self, request, pk=None):
|
||||
@@ -361,16 +428,36 @@ class InterfaceViewSet(ModelViewSet):
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
class FrontPortViewSet(ModelViewSet):
|
||||
queryset = FrontPort.objects.select_related(
|
||||
'device__device_type__manufacturer', 'rear_port', 'cable'
|
||||
).prefetch_related(
|
||||
'tags'
|
||||
)
|
||||
serializer_class = serializers.FrontPortSerializer
|
||||
filterset_class = filters.FrontPortFilter
|
||||
|
||||
|
||||
class RearPortViewSet(ModelViewSet):
|
||||
queryset = RearPort.objects.select_related(
|
||||
'device__device_type__manufacturer', 'cable'
|
||||
).prefetch_related(
|
||||
'tags'
|
||||
)
|
||||
serializer_class = serializers.RearPortSerializer
|
||||
filterset_class = filters.RearPortFilter
|
||||
|
||||
|
||||
class DeviceBayViewSet(ModelViewSet):
|
||||
queryset = DeviceBay.objects.select_related('installed_device').prefetch_related('tags')
|
||||
serializer_class = serializers.DeviceBaySerializer
|
||||
filter_class = filters.DeviceBayFilter
|
||||
filterset_class = filters.DeviceBayFilter
|
||||
|
||||
|
||||
class InventoryItemViewSet(ModelViewSet):
|
||||
queryset = InventoryItem.objects.select_related('device', 'manufacturer').prefetch_related('tags')
|
||||
serializer_class = serializers.InventoryItemSerializer
|
||||
filter_class = filters.InventoryItemFilter
|
||||
filterset_class = filters.InventoryItemFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -378,21 +465,47 @@ class InventoryItemViewSet(ModelViewSet):
|
||||
#
|
||||
|
||||
class ConsoleConnectionViewSet(ListModelMixin, GenericViewSet):
|
||||
queryset = ConsolePort.objects.select_related('device', 'cs_port__device').filter(cs_port__isnull=False)
|
||||
queryset = ConsolePort.objects.select_related(
|
||||
'device', 'connected_endpoint__device'
|
||||
).filter(
|
||||
connected_endpoint__isnull=False
|
||||
)
|
||||
serializer_class = serializers.ConsolePortSerializer
|
||||
filter_class = filters.ConsoleConnectionFilter
|
||||
filterset_class = filters.ConsoleConnectionFilter
|
||||
|
||||
|
||||
class PowerConnectionViewSet(ListModelMixin, GenericViewSet):
|
||||
queryset = PowerPort.objects.select_related('device', 'power_outlet__device').filter(power_outlet__isnull=False)
|
||||
queryset = PowerPort.objects.select_related(
|
||||
'device', 'connected_endpoint__device'
|
||||
).filter(
|
||||
connected_endpoint__isnull=False
|
||||
)
|
||||
serializer_class = serializers.PowerPortSerializer
|
||||
filter_class = filters.PowerConnectionFilter
|
||||
filterset_class = filters.PowerConnectionFilter
|
||||
|
||||
|
||||
class InterfaceConnectionViewSet(ModelViewSet):
|
||||
queryset = InterfaceConnection.objects.select_related('interface_a__device', 'interface_b__device')
|
||||
queryset = Interface.objects.select_related(
|
||||
'device', '_connected_interface', '_connected_circuittermination'
|
||||
).filter(
|
||||
# Avoid duplicate connections by only selecting the lower PK in a connected pair
|
||||
Q(_connected_interface__isnull=False, pk__lt=F('_connected_interface')) |
|
||||
Q(_connected_circuittermination__isnull=False)
|
||||
)
|
||||
serializer_class = serializers.InterfaceConnectionSerializer
|
||||
filter_class = filters.InterfaceConnectionFilter
|
||||
filterset_class = filters.InterfaceConnectionFilter
|
||||
|
||||
|
||||
#
|
||||
# Cables
|
||||
#
|
||||
|
||||
class CableViewSet(ModelViewSet):
|
||||
queryset = Cable.objects.prefetch_related(
|
||||
'termination_a', 'termination_b'
|
||||
)
|
||||
serializer_class = serializers.CableSerializer
|
||||
filterset_class = filters.CableFilter
|
||||
|
||||
|
||||
#
|
||||
@@ -418,32 +531,39 @@ class ConnectedDeviceViewSet(ViewSet):
|
||||
* `peer_interface`: The name of the peer interface
|
||||
"""
|
||||
permission_classes = [IsAuthenticatedOrLoginNotRequired]
|
||||
_device_param = Parameter('peer_device', 'query',
|
||||
description='The name of the peer device', required=True, type=openapi.TYPE_STRING)
|
||||
_interface_param = Parameter('peer_interface', 'query',
|
||||
description='The name of the peer interface', required=True, type=openapi.TYPE_STRING)
|
||||
_device_param = Parameter(
|
||||
name='peer_device',
|
||||
in_='query',
|
||||
description='The name of the peer device',
|
||||
required=True,
|
||||
type=openapi.TYPE_STRING
|
||||
)
|
||||
_interface_param = Parameter(
|
||||
name='peer_interface',
|
||||
in_='query',
|
||||
description='The name of the peer interface',
|
||||
required=True,
|
||||
type=openapi.TYPE_STRING
|
||||
)
|
||||
|
||||
def get_view_name(self):
|
||||
return "Connected Device Locator"
|
||||
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[_device_param, _interface_param], responses={'200': serializers.DeviceSerializer})
|
||||
manual_parameters=[_device_param, _interface_param],
|
||||
responses={'200': serializers.DeviceSerializer}
|
||||
)
|
||||
def list(self, request):
|
||||
|
||||
peer_device_name = request.query_params.get(self._device_param.name)
|
||||
if not peer_device_name:
|
||||
# TODO: remove this after 2.4 as the switch to using underscores is a breaking change
|
||||
peer_device_name = request.query_params.get('peer-device')
|
||||
peer_interface_name = request.query_params.get(self._interface_param.name)
|
||||
if not peer_interface_name:
|
||||
# TODO: remove this after 2.4 as the switch to using underscores is a breaking change
|
||||
peer_interface_name = request.query_params.get('peer-interface')
|
||||
|
||||
if not peer_device_name or not peer_interface_name:
|
||||
raise MissingFilterException(detail='Request must include "peer_device" and "peer_interface" filters.')
|
||||
|
||||
# Determine local interface from peer interface's connection
|
||||
peer_interface = get_object_or_404(Interface, device__name=peer_device_name, name=peer_interface_name)
|
||||
local_interface = peer_interface.connected_interface
|
||||
local_interface = peer_interface._connected_interface
|
||||
|
||||
if local_interface is None:
|
||||
return Response()
|
||||
|
Reference in New Issue
Block a user