Beispiel #1
0
class CustomFieldSerializer(ValidatedModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="extras-api:customfield-detail")
    content_types = ContentTypeField(
        queryset=ContentType.objects.filter(
            FeatureQuery("custom_fields").get_query()),
        many=True,
    )
    type = ChoiceField(choices=CustomFieldTypeChoices)
    filter_logic = ChoiceField(choices=CustomFieldFilterLogicChoices,
                               required=False)

    class Meta:
        model = CustomField
        fields = [
            "id",
            "url",
            "content_types",
            "type",
            "name",
            "label",
            "description",
            "required",
            "filter_logic",
            "default",
            "weight",
            "validation_minimum",
            "validation_maximum",
            "validation_regex",
        ]
Beispiel #2
0
class PowerOutletTemplateSerializer(CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="dcim-api:poweroutlettemplate-detail")
    device_type = NestedDeviceTypeSerializer()
    type = ChoiceField(choices=PowerOutletTypeChoices,
                       allow_blank=True,
                       required=False)
    power_port = NestedPowerPortTemplateSerializer(required=False)
    feed_leg = ChoiceField(choices=PowerOutletFeedLegChoices,
                           allow_blank=True,
                           required=False)

    class Meta:
        model = PowerOutletTemplate
        fields = [
            "id",
            "url",
            "device_type",
            "name",
            "label",
            "type",
            "power_port",
            "feed_leg",
            "description",
            "custom_fields",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]
Beispiel #3
0
class PowerOutletSerializer(
    TaggedObjectSerializer,
    CableTerminationSerializer,
    ConnectedEndpointSerializer,
    CustomFieldModelSerializer,
):
    url = serializers.HyperlinkedIdentityField(view_name="dcim-api:poweroutlet-detail")
    device = NestedDeviceSerializer()
    type = ChoiceField(choices=PowerOutletTypeChoices, allow_blank=True, required=False)
    power_port = NestedPowerPortSerializer(required=False)
    feed_leg = ChoiceField(choices=PowerOutletFeedLegChoices, allow_blank=True, required=False)
    cable = NestedCableSerializer(read_only=True)

    class Meta:
        model = PowerOutlet
        fields = [
            "id",
            "url",
            "device",
            "name",
            "label",
            "type",
            "power_port",
            "feed_leg",
            "description",
            "cable",
            "cable_peer",
            "cable_peer_type",
            "connected_endpoint",
            "connected_endpoint_type",
            "connected_endpoint_reachable",
            "tags",
            "custom_fields",
        ]
Beispiel #4
0
class RackSerializer(TaggedObjectSerializer, StatusModelSerializerMixin, CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="dcim-api:rack-detail")
    site = NestedSiteSerializer()
    group = NestedRackGroupSerializer(required=False, allow_null=True, default=None)
    tenant = NestedTenantSerializer(required=False, allow_null=True)
    role = NestedRackRoleSerializer(required=False, allow_null=True)
    type = ChoiceField(choices=RackTypeChoices, allow_blank=True, required=False)
    width = ChoiceField(choices=RackWidthChoices, required=False)
    outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False)
    device_count = serializers.IntegerField(read_only=True)
    powerfeed_count = serializers.IntegerField(read_only=True)

    class Meta:
        model = Rack
        fields = [
            "id",
            "url",
            "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",
            "device_count",
            "powerfeed_count",
        ]
        # Omit the UniqueTogetherValidator that would be automatically added to validate (group, facility_id). This
        # prevents facility_id from being interpreted as a required field.
        validators = [UniqueTogetherValidator(queryset=Rack.objects.all(), fields=("group", "name"))]

    def validate(self, data):

        # Validate uniqueness of (group, facility_id) since we omitted the automatically-created validator from Meta.
        if data.get("facility_id", None):
            validator = UniqueTogetherValidator(queryset=Rack.objects.all(), fields=("group", "facility_id"))
            validator(data, self)

        # Enforce model validation
        super().validate(data)

        return data
Beispiel #5
0
class IPAddressSerializer(TaggedObjectSerializer, StatusModelSerializerMixin,
                          CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="ipam-api:ipaddress-detail")
    family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
    address = IPFieldSerializer()
    vrf = NestedVRFSerializer(required=False, allow_null=True)
    tenant = NestedTenantSerializer(required=False, allow_null=True)
    role = ChoiceField(choices=IPAddressRoleChoices,
                       allow_blank=True,
                       required=False)
    assigned_object_type = ContentTypeField(
        queryset=ContentType.objects.filter(
            constants.IPADDRESS_ASSIGNMENT_MODELS),
        required=False,
        allow_null=True,
    )
    assigned_object = serializers.SerializerMethodField(read_only=True)
    nat_inside = NestedIPAddressSerializer(required=False, allow_null=True)
    nat_outside = NestedIPAddressSerializer(read_only=True)

    class Meta:
        model = IPAddress
        fields = [
            "id",
            "url",
            "family",
            "address",
            "vrf",
            "tenant",
            "status",
            "role",
            "assigned_object_type",
            "assigned_object_id",
            "assigned_object",
            "nat_inside",
            "nat_outside",
            "dns_name",
            "description",
            "tags",
            "custom_fields",
            "created",
            "last_updated",
            "computed_fields",
        ]
        read_only_fields = ["family"]
        opt_in_fields = ["computed_fields"]

    @swagger_serializer_method(serializer_or_field=serializers.DictField)
    def get_assigned_object(self, obj):
        if obj.assigned_object is None:
            return None
        serializer = get_serializer_for_model(obj.assigned_object,
                                              prefix="Nested")
        context = {"request": self.context["request"]}
        return serializer(obj.assigned_object, context=context).data
Beispiel #6
0
class PowerFeedSerializer(
        TaggedObjectSerializer,
        CableTerminationSerializer,
        ConnectedEndpointSerializer,
        StatusModelSerializerMixin,
        CustomFieldModelSerializer,
):
    url = serializers.HyperlinkedIdentityField(
        view_name="dcim-api:powerfeed-detail")
    power_panel = NestedPowerPanelSerializer()
    rack = NestedRackSerializer(required=False, allow_null=True, default=None)
    type = ChoiceField(choices=PowerFeedTypeChoices,
                       default=PowerFeedTypeChoices.TYPE_PRIMARY)
    supply = ChoiceField(choices=PowerFeedSupplyChoices,
                         default=PowerFeedSupplyChoices.SUPPLY_AC)
    phase = ChoiceField(choices=PowerFeedPhaseChoices,
                        default=PowerFeedPhaseChoices.PHASE_SINGLE)
    cable = NestedCableSerializer(read_only=True)

    class Meta:
        model = PowerFeed
        fields = [
            "id",
            "url",
            "power_panel",
            "rack",
            "name",
            "status",
            "type",
            "supply",
            "phase",
            "voltage",
            "amperage",
            "max_utilization",
            "comments",
            "cable",
            "cable_peer",
            "cable_peer_type",
            "connected_endpoint",
            "connected_endpoint_type",
            "connected_endpoint_reachable",
            "tags",
            "custom_fields",
            "created",
            "last_updated",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]
Beispiel #7
0
class JobResultSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="extras-api:jobresult-detail")
    user = NestedUserSerializer(read_only=True)
    status = ChoiceField(choices=JobResultStatusChoices, read_only=True)
    job_model = NestedJobSerializer(read_only=True)
    obj_type = ContentTypeField(read_only=True)
    schedule = NestedScheduledJobSerializer(read_only=True)

    class Meta:
        model = JobResult
        fields = [
            "id",
            "url",
            "created",
            "completed",
            "name",
            "job_model",
            "obj_type",
            "status",
            "user",
            "data",
            "job_id",
            "schedule",
        ]
Beispiel #8
0
class PrefixSerializer(TaggedObjectSerializer, StatusModelSerializerMixin,
                       CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="ipam-api:prefix-detail")
    family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
    prefix = IPFieldSerializer()
    site = NestedSiteSerializer(required=False, allow_null=True)
    vrf = NestedVRFSerializer(required=False, allow_null=True)
    tenant = NestedTenantSerializer(required=False, allow_null=True)
    vlan = NestedVLANSerializer(required=False, allow_null=True)
    role = NestedRoleSerializer(required=False, allow_null=True)

    class Meta:
        model = Prefix
        fields = [
            "id",
            "url",
            "family",
            "prefix",
            "site",
            "vrf",
            "tenant",
            "vlan",
            "status",
            "role",
            "is_pool",
            "description",
            "tags",
            "custom_fields",
            "created",
            "last_updated",
            "computed_fields",
        ]
        read_only_fields = ["family"]
        opt_in_fields = ["computed_fields"]
Beispiel #9
0
class ServiceSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="ipam-api:service-detail")
    device = NestedDeviceSerializer(required=False, allow_null=True)
    virtual_machine = NestedVirtualMachineSerializer(required=False,
                                                     allow_null=True)
    protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
    ipaddresses = SerializedPKRelatedField(
        queryset=IPAddress.objects.all(),
        serializer=NestedIPAddressSerializer,
        required=False,
        many=True,
    )
    ports = serializers.ListField(child=serializers.IntegerField(
        min_value=constants.SERVICE_PORT_MIN,
        max_value=constants.SERVICE_PORT_MAX,
    ))

    class Meta:
        model = Service
        fields = [
            "id",
            "url",
            "device",
            "virtual_machine",
            "name",
            "ports",
            "protocol",
            "ipaddresses",
            "description",
            "tags",
            "custom_fields",
            "created",
            "last_updated",
        ]
Beispiel #10
0
class ConsolePortSerializer(
        TaggedObjectSerializer,
        CableTerminationSerializer,
        ConnectedEndpointSerializer,
        CustomFieldModelSerializer,
):
    url = serializers.HyperlinkedIdentityField(
        view_name="dcim-api:consoleport-detail")
    device = NestedDeviceSerializer()
    type = ChoiceField(choices=ConsolePortTypeChoices,
                       allow_blank=True,
                       required=False)
    cable = NestedCableSerializer(read_only=True)

    class Meta:
        model = ConsolePort
        fields = [
            "id",
            "url",
            "device",
            "name",
            "label",
            "type",
            "description",
            "cable",
            "cable_peer",
            "cable_peer_type",
            "connected_endpoint",
            "connected_endpoint_type",
            "connected_endpoint_reachable",
            "tags",
            "custom_fields",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]
Beispiel #11
0
class DeviceTypeSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="dcim-api:devicetype-detail")
    manufacturer = NestedManufacturerSerializer()
    subdevice_role = ChoiceField(choices=SubdeviceRoleChoices,
                                 allow_blank=True,
                                 required=False)
    device_count = serializers.IntegerField(read_only=True)

    class Meta:
        model = DeviceType
        fields = [
            "id",
            "url",
            "manufacturer",
            "model",
            "slug",
            "part_number",
            "u_height",
            "is_full_depth",
            "subdevice_role",
            "front_image",
            "rear_image",
            "comments",
            "tags",
            "custom_fields",
            "created",
            "last_updated",
            "device_count",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]
Beispiel #12
0
class AggregateSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="ipam-api:aggregate-detail")
    family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
    prefix = IPFieldSerializer()
    rir = NestedRIRSerializer()
    tenant = NestedTenantSerializer(required=False, allow_null=True)

    class Meta:
        model = Aggregate
        fields = [
            "id",
            "url",
            "family",
            "prefix",
            "rir",
            "tenant",
            "date_added",
            "description",
            "tags",
            "custom_fields",
            "created",
            "last_updated",
            "computed_fields",
        ]
        read_only_fields = ["family"]
        opt_in_fields = ["computed_fields"]
Beispiel #13
0
class FrontPortSerializer(TaggedObjectSerializer, CableTerminationSerializer,
                          CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="dcim-api:frontport-detail")
    device = NestedDeviceSerializer()
    type = ChoiceField(choices=PortTypeChoices)
    rear_port = FrontPortRearPortSerializer()
    cable = NestedCableSerializer(read_only=True)

    class Meta:
        model = FrontPort
        fields = [
            "id",
            "url",
            "device",
            "name",
            "label",
            "type",
            "rear_port",
            "rear_port_position",
            "description",
            "cable",
            "cable_peer",
            "cable_peer_type",
            "tags",
            "custom_fields",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]
Beispiel #14
0
class CableSerializer(TaggedObjectSerializer, StatusModelSerializerMixin,
                      CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="dcim-api:cable-detail")
    termination_a_type = ContentTypeField(
        queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS))
    termination_b_type = ContentTypeField(
        queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS))
    termination_a = serializers.SerializerMethodField(read_only=True)
    termination_b = serializers.SerializerMethodField(read_only=True)
    length_unit = ChoiceField(choices=CableLengthUnitChoices,
                              allow_blank=True,
                              required=False)

    class Meta:
        model = Cable
        fields = [
            "id",
            "url",
            "termination_a_type",
            "termination_a_id",
            "termination_a",
            "termination_b_type",
            "termination_b_id",
            "termination_b",
            "type",
            "status",
            "label",
            "color",
            "length",
            "length_unit",
            "tags",
            "custom_fields",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]

    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

    @swagger_serializer_method(serializer_or_field=serializers.DictField)
    def get_termination_a(self, obj):
        return self._get_termination(obj, "a")

    @swagger_serializer_method(serializer_or_field=serializers.DictField)
    def get_termination_b(self, obj):
        return self._get_termination(obj, "b")
Beispiel #15
0
class NestedJobResultSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="extras-api:jobresult-detail")
    status = ChoiceField(choices=choices.JobResultStatusChoices)
    user = NestedUserSerializer(read_only=True)

    class Meta:
        model = models.JobResult
        fields = ["url", "created", "completed", "user", "status"]
Beispiel #16
0
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.
    """

    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(read_only=True)
    face = ChoiceField(choices=DeviceFaceChoices, read_only=True)
    device = NestedDeviceSerializer(read_only=True)
    occupied = serializers.BooleanField(read_only=True)
Beispiel #17
0
class DeviceTypeSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="dcim-api:devicetype-detail")
    manufacturer = NestedManufacturerSerializer()
    subdevice_role = ChoiceField(choices=SubdeviceRoleChoices,
                                 allow_blank=True,
                                 required=False)
    device_count = serializers.IntegerField(read_only=True)

    class Meta:
        model = DeviceType
        fields = [
            "id",
            "url",
            "manufacturer",
            "model",
            "slug",
            "part_number",
            "u_height",
            "is_full_depth",
            "subdevice_role",
            "front_image",
            "rear_image",
            "comments",
            "tags",
            "custom_fields",
            "created",
            "last_updated",
            "device_count",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]
        # Omit the UniqueTogetherValidator that would be automatically added to validate (manufacturer, slug). This
        # prevents slug from being interpreted as a required field.
        # TODO: Remove if/when slug is globally unique. This would be a breaking change.
        validators = [
            UniqueTogetherValidator(queryset=DeviceType.objects.all(),
                                    fields=("manufacturer", "model"))
        ]

    def validate(self, data):
        # Validate uniqueness of (manufacturer, slug) since we omitted the automatically-created validator from Meta.
        # TODO: Remove if/when slug is globally unique. This would be a breaking change.
        if data.get("slug", None):
            validator = UniqueTogetherValidator(
                queryset=DeviceType.objects.all(),
                fields=("manufacturer", "slug"))
            validator(data, self)

        # Enforce model validation
        super().validate(data)

        return data
Beispiel #18
0
class ConsoleServerPortTemplateSerializer(CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="dcim-api:consoleserverporttemplate-detail")
    device_type = NestedDeviceTypeSerializer()
    type = ChoiceField(choices=ConsolePortTypeChoices, allow_blank=True, required=False)

    class Meta:
        model = ConsoleServerPortTemplate
        fields = [
            "id",
            "url",
            "device_type",
            "name",
            "label",
            "type",
            "description",
            "custom_fields",
        ]
Beispiel #19
0
class VMInterfaceSerializer(TaggedObjectSerializer, ValidatedModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="virtualization-api:vminterface-detail")
    virtual_machine = NestedVirtualMachineSerializer()
    mode = ChoiceField(choices=InterfaceModeChoices,
                       allow_blank=True,
                       required=False)
    untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
    tagged_vlans = SerializedPKRelatedField(
        queryset=VLAN.objects.all(),
        serializer=NestedVLANSerializer,
        required=False,
        many=True,
    )

    class Meta:
        model = VMInterface
        fields = [
            "id",
            "url",
            "virtual_machine",
            "name",
            "enabled",
            "mtu",
            "mac_address",
            "description",
            "mode",
            "untagged_vlan",
            "tagged_vlans",
            "tags",
        ]

    def validate(self, data):

        # Validate many-to-many VLAN assignments
        virtual_machine = self.instance.virtual_machine if self.instance else data.get(
            "virtual_machine")
        for vlan in data.get("tagged_vlans", []):
            if vlan.site not in [virtual_machine.site, None]:
                raise serializers.ValidationError({
                    "tagged_vlans":
                    f"VLAN {vlan} must belong to the same site as the interface's parent virtual "
                    f"machine, or it must be global."
                })

        return super().validate(data)
Beispiel #20
0
class InterfaceTemplateSerializer(CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="dcim-api:interfacetemplate-detail")
    device_type = NestedDeviceTypeSerializer()
    type = ChoiceField(choices=InterfaceTypeChoices)

    class Meta:
        model = InterfaceTemplate
        fields = [
            "id",
            "url",
            "device_type",
            "name",
            "label",
            "type",
            "mgmt_only",
            "description",
            "custom_fields",
        ]
Beispiel #21
0
class RearPortTemplateSerializer(CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="dcim-api:rearporttemplate-detail")
    device_type = NestedDeviceTypeSerializer()
    type = ChoiceField(choices=PortTypeChoices)

    class Meta:
        model = RearPortTemplate
        fields = [
            "id",
            "url",
            "device_type",
            "name",
            "label",
            "type",
            "positions",
            "description",
            "custom_fields",
        ]
Beispiel #22
0
class ObjectChangeSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="extras-api:objectchange-detail")
    user = NestedUserSerializer(read_only=True)
    action = ChoiceField(choices=ObjectChangeActionChoices, read_only=True)
    changed_object_type = ContentTypeField(read_only=True)
    changed_object = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = ObjectChange
        fields = [
            "id",
            "url",
            "time",
            "user",
            "user_name",
            "request_id",
            "action",
            "changed_object_type",
            "changed_object_id",
            "changed_object",
            "object_data",
        ]

    @swagger_serializer_method(serializer_or_field=serializers.DictField)
    def get_changed_object(self, obj):
        """
        Serialize a nested representation of the changed object.
        """
        if obj.changed_object is None:
            return None

        try:
            serializer = get_serializer_for_model(obj.changed_object,
                                                  prefix="Nested")
        except SerializerNotFound:
            return obj.object_repr
        context = {"request": self.context["request"]}
        data = serializer(obj.changed_object, context=context).data

        return data
Beispiel #23
0
class PowerPortTemplateSerializer(CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="dcim-api:powerporttemplate-detail")
    device_type = NestedDeviceTypeSerializer()
    type = ChoiceField(choices=PowerPortTypeChoices, allow_blank=True, required=False)

    class Meta:
        model = PowerPortTemplate
        fields = [
            "id",
            "url",
            "device_type",
            "name",
            "label",
            "type",
            "maximum_draw",
            "allocated_draw",
            "description",
            "custom_fields",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]
Beispiel #24
0
class FrontPortTemplateSerializer(CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="dcim-api:frontporttemplate-detail")
    device_type = NestedDeviceTypeSerializer()
    type = ChoiceField(choices=PortTypeChoices)
    rear_port = NestedRearPortTemplateSerializer()

    class Meta:
        model = FrontPortTemplate
        fields = [
            "id",
            "url",
            "device_type",
            "name",
            "label",
            "type",
            "rear_port",
            "rear_port_position",
            "description",
            "custom_fields",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]
Beispiel #25
0
class InterfaceSerializer(
        TaggedObjectSerializer,
        CableTerminationSerializer,
        ConnectedEndpointSerializer,
        CustomFieldModelSerializer,
):
    url = serializers.HyperlinkedIdentityField(
        view_name="dcim-api:interface-detail")
    device = NestedDeviceSerializer()
    type = ChoiceField(choices=InterfaceTypeChoices)
    lag = NestedInterfaceSerializer(required=False, allow_null=True)
    mode = ChoiceField(choices=InterfaceModeChoices,
                       allow_blank=True,
                       required=False)
    untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
    tagged_vlans = SerializedPKRelatedField(
        queryset=VLAN.objects.all(),
        serializer=NestedVLANSerializer,
        required=False,
        many=True,
    )
    cable = NestedCableSerializer(read_only=True)
    count_ipaddresses = serializers.IntegerField(read_only=True)

    class Meta:
        model = Interface
        fields = [
            "id",
            "url",
            "device",
            "name",
            "label",
            "type",
            "enabled",
            "lag",
            "mtu",
            "mac_address",
            "mgmt_only",
            "description",
            "mode",
            "untagged_vlan",
            "tagged_vlans",
            "cable",
            "cable_peer",
            "cable_peer_type",
            "connected_endpoint",
            "connected_endpoint_type",
            "connected_endpoint_reachable",
            "tags",
            "count_ipaddresses",
            "custom_fields",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]

    def validate(self, data):

        # Validate many-to-many VLAN assignments
        device = self.instance.device if self.instance else data.get("device")
        for vlan in data.get("tagged_vlans", []):
            if vlan.site not in [device.site, None]:
                raise serializers.ValidationError({
                    "tagged_vlans":
                    f"VLAN {vlan} must belong to the same site as the interface's parent device, or "
                    f"it must be global."
                })

        return super().validate(data)
Beispiel #26
0
class DeviceSerializer(TaggedObjectSerializer, StatusModelSerializerMixin,
                       CustomFieldModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name="dcim-api:device-detail")
    device_type = NestedDeviceTypeSerializer()
    device_role = NestedDeviceRoleSerializer()
    tenant = NestedTenantSerializer(required=False, allow_null=True)
    platform = NestedPlatformSerializer(required=False, allow_null=True)
    site = NestedSiteSerializer()
    rack = NestedRackSerializer(required=False, allow_null=True)
    face = ChoiceField(choices=DeviceFaceChoices,
                       allow_blank=True,
                       required=False)
    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 = NestedVirtualChassisSerializer(required=False,
                                                     allow_null=True)
    local_context_schema = NestedConfigContextSchemaSerializer(required=False,
                                                               allow_null=True)

    class Meta:
        model = Device
        fields = [
            "id",
            "url",
            "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",
            "local_context_schema",
            "local_context_data",
            "tags",
            "custom_fields",
            "created",
            "last_updated",
            "computed_fields",
        ]
        opt_in_fields = ["computed_fields"]
        validators = []

    def validate(self, data):

        # Validate uniqueness of (rack, position, face) since we omitted the automatically-created validator from Meta.
        if data.get("rack") and data.get("position") and data.get("face"):
            validator = UniqueTogetherValidator(queryset=Device.objects.all(),
                                                fields=("rack", "position",
                                                        "face"))
            validator(data, self)

        # Enforce model validation
        super().validate(data)

        return data

    @swagger_serializer_method(serializer_or_field=NestedDeviceSerializer)
    def get_parent_device(self, obj):
        try:
            device_bay = obj.parent_bay
        except DeviceBay.DoesNotExist:
            return None
        context = {"request": self.context["request"]}
        data = NestedDeviceSerializer(instance=device_bay.device,
                                      context=context).data
        data["device_bay"] = NestedDeviceBaySerializer(instance=device_bay,
                                                       context=context).data
        return data