Skip to content

Field Serviceable Units API Package

nautobot_fsus.api

mixins

Classes to handle user-definable fields and common validations.

FSUModelSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Extend the standard Nautobot model serializer with FSU-specific validations.

Source code in nautobot_fsus/api/mixins.py
class FSUModelSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Extend the standard Nautobot model serializer with FSU-specific validations."""

    class Meta:
        """FSUModelSerializer model options."""

        abstract = True
        fields = "__all__"
        extra_kwargs = {
            "device": {"required": False, "allow_null": True},
            "location": {"required": False, "allow_null": True},
        }

    def validate(self, data: dict[str, Any]) -> dict[str, Any]:
        """Validate the incoming POST/PUT/PATCH data."""
        # FSUs can be assigned to a Device or Location, but not both.
        if data.get("device") is not None and data.get("location") is not None:
            raise serializers.ValidationError(
                "FSUs must be assigned to either a Device or a Storage location, but not both"
            )

        # When changing from a Device to a Storage Location using a PATCH request, only the
        # storage_location field will be present in the data, causing validation to fail because
        # when it runs the FSU will still have a parent Device too...
        if data.get("location") is not None and not data.get("device", False):
            data["device"] = None
        super().validate(data)
        return data

    def run_validators(self, value):
        """
        Test the given value against all the validators on the field.

        Have to provide our own version of this because FSUs have two unique together constraints,
        but only one of this is valid for any given instance - either (name, device)
        or (name, location). If you try to check both, one of them will always raise an error
        because its field is missing.
        """
        errors = []

        # Add read_only fields with defaults to value before running validators.
        if isinstance(value, dict):
            to_validate = self._read_only_defaults()
            to_validate.update(value)
        else:
            to_validate = value

        # Need to filter the unique together validators to use either the device field or
        # the location field, depending on the parent.
        for validator in self.validators:
            if isinstance(validator, UniqueTogetherValidator):
                if to_validate.get("device") and "location" in validator.fields:
                    continue
                if to_validate.get("location") and "device" in validator.fields:
                    continue
            try:
                if getattr(validator, "requires_context", False):
                    validator(to_validate, self)
                else:
                    validator(to_validate)
            except serializers.ValidationError as exc:
                # If the validation error contains a mapping of fields to
                # errors then simply raise it immediately rather than
                # attempting to accumulate a list of errors.
                if isinstance(exc.detail, dict):
                    raise
                errors.extend(exc.detail)
            except DjangoValidationError as exc:
                errors.extend(get_error_detail(exc))
        if errors:
            raise serializers.ValidationError(errors)
Meta

FSUModelSerializer model options.

Source code in nautobot_fsus/api/mixins.py
class Meta:
    """FSUModelSerializer model options."""

    abstract = True
    fields = "__all__"
    extra_kwargs = {
        "device": {"required": False, "allow_null": True},
        "location": {"required": False, "allow_null": True},
    }
run_validators(value)

Test the given value against all the validators on the field.

Have to provide our own version of this because FSUs have two unique together constraints, but only one of this is valid for any given instance - either (name, device) or (name, location). If you try to check both, one of them will always raise an error because its field is missing.

Source code in nautobot_fsus/api/mixins.py
def run_validators(self, value):
    """
    Test the given value against all the validators on the field.

    Have to provide our own version of this because FSUs have two unique together constraints,
    but only one of this is valid for any given instance - either (name, device)
    or (name, location). If you try to check both, one of them will always raise an error
    because its field is missing.
    """
    errors = []

    # Add read_only fields with defaults to value before running validators.
    if isinstance(value, dict):
        to_validate = self._read_only_defaults()
        to_validate.update(value)
    else:
        to_validate = value

    # Need to filter the unique together validators to use either the device field or
    # the location field, depending on the parent.
    for validator in self.validators:
        if isinstance(validator, UniqueTogetherValidator):
            if to_validate.get("device") and "location" in validator.fields:
                continue
            if to_validate.get("location") and "device" in validator.fields:
                continue
        try:
            if getattr(validator, "requires_context", False):
                validator(to_validate, self)
            else:
                validator(to_validate)
        except serializers.ValidationError as exc:
            # If the validation error contains a mapping of fields to
            # errors then simply raise it immediately rather than
            # attempting to accumulate a list of errors.
            if isinstance(exc.detail, dict):
                raise
            errors.extend(exc.detail)
        except DjangoValidationError as exc:
            errors.extend(get_error_detail(exc))
    if errors:
        raise serializers.ValidationError(errors)
validate(data)

Validate the incoming POST/PUT/PATCH data.

Source code in nautobot_fsus/api/mixins.py
def validate(self, data: dict[str, Any]) -> dict[str, Any]:
    """Validate the incoming POST/PUT/PATCH data."""
    # FSUs can be assigned to a Device or Location, but not both.
    if data.get("device") is not None and data.get("location") is not None:
        raise serializers.ValidationError(
            "FSUs must be assigned to either a Device or a Storage location, but not both"
        )

    # When changing from a Device to a Storage Location using a PATCH request, only the
    # storage_location field will be present in the data, causing validation to fail because
    # when it runs the FSU will still have a parent Device too...
    if data.get("location") is not None and not data.get("device", False):
        data["device"] = None
    super().validate(data)
    return data

FSUTemplateModelSerializer

Bases: NautobotModelSerializer

Base class for FSU template serializers.

Source code in nautobot_fsus/api/mixins.py
class FSUTemplateModelSerializer(NautobotModelSerializer):
    """Base class for FSU template serializers."""

    class Meta:
        """FSUTemplateModelSerializer model options."""

        abstract = True
        fields = "__all__"
Meta

FSUTemplateModelSerializer model options.

Source code in nautobot_fsus/api/mixins.py
class Meta:
    """FSUTemplateModelSerializer model options."""

    abstract = True
    fields = "__all__"

FSUTypeModelSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Base class for FSU type serializers.

Source code in nautobot_fsus/api/mixins.py
class FSUTypeModelSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Base class for FSU type serializers."""

    instance_count = serializers.IntegerField(read_only=True)

    class Meta:
        """FSUTypeModelSerializer model options."""

        abstract = True
        fields = "__all__"
Meta

FSUTypeModelSerializer model options.

Source code in nautobot_fsus/api/mixins.py
class Meta:
    """FSUTypeModelSerializer model options."""

    abstract = True
    fields = "__all__"

serializers

API serializers for Nautobot FSUs app models.

CPUSerializer

Bases: FSUModelSerializer

API serializer for CPU model.

Source code in nautobot_fsus/api/serializers/fsus.py
class CPUSerializer(FSUModelSerializer):
    """API serializer for CPU model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:cpu-detail")

    class Meta(FSUModelSerializer.Meta):
        """CPUserializer model options."""

        model = CPU
Meta

Bases: Meta

CPUserializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """CPUserializer model options."""

    model = CPU

CPUTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for CPUTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class CPUTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for CPUTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:cputemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """CPUTemplateSerializer model options."""

        model = CPUTemplate
Meta

Bases: Meta

CPUTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """CPUTemplateSerializer model options."""

    model = CPUTemplate

CPUTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for CPUType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class CPUTypeSerializer(FSUTypeModelSerializer):
    """API serializer for CPUType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:cputype-detail"
    )

    architecture = ChoiceField(choices=choices.CPUArchitectures)

    class Meta(FSUTypeModelSerializer.Meta):
        """CPUTypeSerializer model options."""

        model = CPUType
Meta

Bases: Meta

CPUTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """CPUTypeSerializer model options."""

    model = CPUType

DiskSerializer

Bases: FSUModelSerializer

API serializer for Disk model.

Source code in nautobot_fsus/api/serializers/fsus.py
class DiskSerializer(FSUModelSerializer):
    """API serializer for Disk model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:disk-detail")

    class Meta(FSUModelSerializer.Meta):
        """DiskSerializer model options."""

        model = Disk
Meta

Bases: Meta

DiskSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """DiskSerializer model options."""

    model = Disk

DiskTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for DiskTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class DiskTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for DiskTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:disktemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """DiskTemplateSerializer model options."""

        model = DiskTemplate
Meta

Bases: Meta

DiskTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """DiskTemplateSerializer model options."""

    model = DiskTemplate

DiskTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for DiskType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class DiskTypeSerializer(FSUTypeModelSerializer):
    """API serializer for DiskType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:disktype-detail"
    )

    disk_type = ChoiceField(choices=choices.DiskTypes)

    class Meta(FSUTypeModelSerializer.Meta):
        """DiskTypeSerializer model options."""

        model = DiskType
Meta

Bases: Meta

DiskTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """DiskTypeSerializer model options."""

    model = DiskType

FanSerializer

Bases: FSUModelSerializer

API serializer for Fan model.

Source code in nautobot_fsus/api/serializers/fsus.py
class FanSerializer(FSUModelSerializer):
    """API serializer for Fan model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:fan-detail")

    class Meta(FSUModelSerializer.Meta):
        """FanSerializer model options."""

        model = Fan
Meta

Bases: Meta

FanSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """FanSerializer model options."""

    model = Fan

FanTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for FanTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class FanTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for FanTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:fantemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """FanTemplateSerializer model options."""

        model = FanTemplate
Meta

Bases: Meta

FanTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """FanTemplateSerializer model options."""

    model = FanTemplate

FanTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for FanType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class FanTypeSerializer(FSUTypeModelSerializer):
    """API serializer for FanType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:fantype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """FanTypeSerializer model options."""

        model = FanType
Meta

Bases: Meta

FanTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """FanTypeSerializer model options."""

    model = FanType

GPUBaseboardSerializer

Bases: FSUModelSerializer

API serializer for GPUBaseboard model.

Source code in nautobot_fsus/api/serializers/fsus.py
class GPUBaseboardSerializer(FSUModelSerializer):
    """API serializer for GPUBaseboard model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:gpubaseboard-detail")
    gpus = serializers.PrimaryKeyRelatedField(
        queryset=GPU.objects.all(),
        many=True,
        required=False,
        allow_null=True,
    )

    class Meta(FSUModelSerializer.Meta):
        """GPUBaseboardSerializer model options."""

        model = GPUBaseboard

    def validate(self, data: Any):
        """Need to hide the gpus field from normal validation."""
        to_validate = copy(data)

        # Need to remove the list of gpus before the first validation step, otherwise the
        # model validation will complain because you can't set parent_gpubaseboard on the gpus in
        # this direction, that's handled in the create()/update() methods.
        _ = to_validate.pop("gpus", None)

        super().validate(to_validate)

        return data

    def create(self, validated_data: Any) -> GPUBaseboard:
        """Create a new GPUBaseboard instance with child GPU validation."""
        # gpus is optional in the POST data, set it to an empty list if it's not present.
        gpus = validated_data.pop("gpus", [])

        try:
            with transaction.atomic():
                if gpus:
                    # Validate parent device
                    validate_parent_device(gpus, validated_data.get("device", None))

                    # Validate available slots
                    baseboard_type = validated_data["fsu_type"]
                    if (
                        baseboard_type.slot_count is not None
                        and len(gpus) > baseboard_type.slot_count
                    ):
                        raise ValidationError(
                            f"Number of GPUs being added to Baseboard ({len(gpus)}) is "
                            f"greater than the number of available slots "
                            f"({baseboard_type.slot_count})"
                        )

                    # Child GPUs must not have a parent GPU Baseboard assigned
                    for gpu in gpus:
                        if gpu.parent_gpubaseboard is not None:
                            raise ValidationError(
                                f"GPU {gpu.name} is already assigned to "
                                f"{gpu.parent_gpubaseboard.name}"
                            )

                # Create the GPUBaseboard instance
                instance: GPUBaseboard = GPUBaseboard.objects.create(**validated_data)

                # Set parent_gpubaseboard for any specified child GPU instances
                for gpu in gpus:
                    gpu.parent_gpubaseboard = instance
                    gpu.validated_save()

        except ValidationError as error:
            raise serializers.ValidationError({"gpus": error.messages[0]}) from error

        return instance

    def update(self, instance: GPUBaseboard, validated_data: Any) -> GPUBaseboard:
        """
        Update an existing GPUBaseboard instance.

        PUT requests must have all required field, PATCH requests need only the changed fields.
        When updating a GPUBaseboard instance, child GPUs update logic is:
        - gpus not set or null, device and storage location not updated -> no changes
        - gpus set and device is not set or instance device is None -> ValidationError
        - gpus is an empty list -> clear parent_gpubaseboard on any existing child GPUs
        - gpus is set, device is set or instance.device is not None and any gpu.device is not
            the same as the device value or the instance.device -> ValidationError
        - gpus is set, device is set or instance.device is not None -> set parent_gpubaseboard to
            instance for GPUs in the list, clear parent_gpubaseboard for any that are currently set
            to the instance but are not in the list
        - gpus not set or null and storage location set -> clear any existing child GPUs
        """
        # For update operations we need to know if the gpus field is present in the PUT/PATCH data,
        # as an empty list triggers clearing parent_gpubaseboard for current child GPUs
        gpus = validated_data.pop("gpus", None)

        location = validated_data.get("location", None)
        parent_device = None if location else validated_data.get("device", instance.device)

        try:
            with transaction.atomic():
                # An empty list means we're clearing the child GPUs for this GPUBasebaord
                # Moving a GPUBaseboard to a location means we need to clear any child GPUs
                if (gpus is not None and len(gpus) == 0) or location is not None:
                    for gpu in instance.gpus.all():
                        gpu.parent_gpubaseboard = None
                        gpu.validated_save()

                elif gpus:
                    # Validate the parent device
                    validate_parent_device(gpus, parent_device)

                    # Validate available slots
                    baseboard_type = instance.fsu_type
                    if (
                        baseboard_type.slot_count is not None
                        and len(gpus) > baseboard_type.slot_count
                    ):
                        raise ValidationError(
                            f"Number of GPUs being added to Baseboard ({len(gpus)}) is greater "
                            f"than the number of available slots ({baseboard_type.slot_count})"
                        )

                    # Track the currently set child GPUs to update properly
                    # if the list has changed
                    current_gpus = set(list(instance.gpus.all()))
                    new_gpus = set()
                    for gpu in gpus:
                        # New child GPUs must not have a parent GPUBaseboard assigned
                        if gpu not in current_gpus and gpu.parent_gpubaseboard is not None:
                            raise ValidationError(
                                f"GPU {gpu.name} is already assigned to "
                                f"{gpu.parent_gpubaseboard.name}"
                            )
                        new_gpus.add(gpu)

                    # Set parent_gpubaseboard for newly added child GPUs
                    for new_gpu in new_gpus.difference(current_gpus):
                        new_gpu.parent_gpubaseboard = instance
                        new_gpu.validated_save()

                    # Remove any currently assigned child GPUs that are not in the updated list
                    for gpu in current_gpus.difference(new_gpus):
                        gpu.parent_gpubaseboard = None
                        gpu.validated_save()

                validated_instance: GPUBaseboard = super().update(instance, validated_data)

        except ValidationError as error:
            raise serializers.ValidationError({"gpus": error.messages[0]}) from error

        return validated_instance
Meta

Bases: Meta

GPUBaseboardSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """GPUBaseboardSerializer model options."""

    model = GPUBaseboard
create(validated_data)

Create a new GPUBaseboard instance with child GPU validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def create(self, validated_data: Any) -> GPUBaseboard:
    """Create a new GPUBaseboard instance with child GPU validation."""
    # gpus is optional in the POST data, set it to an empty list if it's not present.
    gpus = validated_data.pop("gpus", [])

    try:
        with transaction.atomic():
            if gpus:
                # Validate parent device
                validate_parent_device(gpus, validated_data.get("device", None))

                # Validate available slots
                baseboard_type = validated_data["fsu_type"]
                if (
                    baseboard_type.slot_count is not None
                    and len(gpus) > baseboard_type.slot_count
                ):
                    raise ValidationError(
                        f"Number of GPUs being added to Baseboard ({len(gpus)}) is "
                        f"greater than the number of available slots "
                        f"({baseboard_type.slot_count})"
                    )

                # Child GPUs must not have a parent GPU Baseboard assigned
                for gpu in gpus:
                    if gpu.parent_gpubaseboard is not None:
                        raise ValidationError(
                            f"GPU {gpu.name} is already assigned to "
                            f"{gpu.parent_gpubaseboard.name}"
                        )

            # Create the GPUBaseboard instance
            instance: GPUBaseboard = GPUBaseboard.objects.create(**validated_data)

            # Set parent_gpubaseboard for any specified child GPU instances
            for gpu in gpus:
                gpu.parent_gpubaseboard = instance
                gpu.validated_save()

    except ValidationError as error:
        raise serializers.ValidationError({"gpus": error.messages[0]}) from error

    return instance
update(instance, validated_data)

Update an existing GPUBaseboard instance.

PUT requests must have all required field, PATCH requests need only the changed fields. When updating a GPUBaseboard instance, child GPUs update logic is: - gpus not set or null, device and storage location not updated -> no changes - gpus set and device is not set or instance device is None -> ValidationError - gpus is an empty list -> clear parent_gpubaseboard on any existing child GPUs - gpus is set, device is set or instance.device is not None and any gpu.device is not the same as the device value or the instance.device -> ValidationError - gpus is set, device is set or instance.device is not None -> set parent_gpubaseboard to instance for GPUs in the list, clear parent_gpubaseboard for any that are currently set to the instance but are not in the list - gpus not set or null and storage location set -> clear any existing child GPUs

Source code in nautobot_fsus/api/serializers/fsus.py
def update(self, instance: GPUBaseboard, validated_data: Any) -> GPUBaseboard:
    """
    Update an existing GPUBaseboard instance.

    PUT requests must have all required field, PATCH requests need only the changed fields.
    When updating a GPUBaseboard instance, child GPUs update logic is:
    - gpus not set or null, device and storage location not updated -> no changes
    - gpus set and device is not set or instance device is None -> ValidationError
    - gpus is an empty list -> clear parent_gpubaseboard on any existing child GPUs
    - gpus is set, device is set or instance.device is not None and any gpu.device is not
        the same as the device value or the instance.device -> ValidationError
    - gpus is set, device is set or instance.device is not None -> set parent_gpubaseboard to
        instance for GPUs in the list, clear parent_gpubaseboard for any that are currently set
        to the instance but are not in the list
    - gpus not set or null and storage location set -> clear any existing child GPUs
    """
    # For update operations we need to know if the gpus field is present in the PUT/PATCH data,
    # as an empty list triggers clearing parent_gpubaseboard for current child GPUs
    gpus = validated_data.pop("gpus", None)

    location = validated_data.get("location", None)
    parent_device = None if location else validated_data.get("device", instance.device)

    try:
        with transaction.atomic():
            # An empty list means we're clearing the child GPUs for this GPUBasebaord
            # Moving a GPUBaseboard to a location means we need to clear any child GPUs
            if (gpus is not None and len(gpus) == 0) or location is not None:
                for gpu in instance.gpus.all():
                    gpu.parent_gpubaseboard = None
                    gpu.validated_save()

            elif gpus:
                # Validate the parent device
                validate_parent_device(gpus, parent_device)

                # Validate available slots
                baseboard_type = instance.fsu_type
                if (
                    baseboard_type.slot_count is not None
                    and len(gpus) > baseboard_type.slot_count
                ):
                    raise ValidationError(
                        f"Number of GPUs being added to Baseboard ({len(gpus)}) is greater "
                        f"than the number of available slots ({baseboard_type.slot_count})"
                    )

                # Track the currently set child GPUs to update properly
                # if the list has changed
                current_gpus = set(list(instance.gpus.all()))
                new_gpus = set()
                for gpu in gpus:
                    # New child GPUs must not have a parent GPUBaseboard assigned
                    if gpu not in current_gpus and gpu.parent_gpubaseboard is not None:
                        raise ValidationError(
                            f"GPU {gpu.name} is already assigned to "
                            f"{gpu.parent_gpubaseboard.name}"
                        )
                    new_gpus.add(gpu)

                # Set parent_gpubaseboard for newly added child GPUs
                for new_gpu in new_gpus.difference(current_gpus):
                    new_gpu.parent_gpubaseboard = instance
                    new_gpu.validated_save()

                # Remove any currently assigned child GPUs that are not in the updated list
                for gpu in current_gpus.difference(new_gpus):
                    gpu.parent_gpubaseboard = None
                    gpu.validated_save()

            validated_instance: GPUBaseboard = super().update(instance, validated_data)

    except ValidationError as error:
        raise serializers.ValidationError({"gpus": error.messages[0]}) from error

    return validated_instance
validate(data)

Need to hide the gpus field from normal validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def validate(self, data: Any):
    """Need to hide the gpus field from normal validation."""
    to_validate = copy(data)

    # Need to remove the list of gpus before the first validation step, otherwise the
    # model validation will complain because you can't set parent_gpubaseboard on the gpus in
    # this direction, that's handled in the create()/update() methods.
    _ = to_validate.pop("gpus", None)

    super().validate(to_validate)

    return data

GPUBaseboardTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for GPUBaseboardTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class GPUBaseboardTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for GPUBaseboardTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:gpubaseboardtemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """GPUBaseboardTemplateSerializer model options."""

        model = GPUBaseboardTemplate
Meta

Bases: Meta

GPUBaseboardTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """GPUBaseboardTemplateSerializer model options."""

    model = GPUBaseboardTemplate

GPUBaseboardTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for GPUBaseboardType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class GPUBaseboardTypeSerializer(FSUTypeModelSerializer):
    """API serializer for GPUBaseboardType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:gpubaseboardtype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """GPUBaseboardTypeSerializer model options."""

        model = GPUBaseboardType
Meta

Bases: Meta

GPUBaseboardTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """GPUBaseboardTypeSerializer model options."""

    model = GPUBaseboardType

GPUSerializer

Bases: FSUModelSerializer

API serializer for GPU model.

Source code in nautobot_fsus/api/serializers/fsus.py
class GPUSerializer(FSUModelSerializer):
    """API serializer for GPU model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:gpu-detail")

    class Meta(FSUModelSerializer.Meta):
        """GPUSerializer model options."""

        model = GPU
Meta

Bases: Meta

GPUSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """GPUSerializer model options."""

    model = GPU

GPUTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for GPUTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class GPUTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for GPUTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:gputemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """GPUTemplateSerializer model options."""

        model = GPUTemplate
Meta

Bases: Meta

GPUTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """GPUTemplateSerializer model options."""

    model = GPUTemplate

GPUTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for GPUType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class GPUTypeSerializer(FSUTypeModelSerializer):
    """API serializer for GPUType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:gputype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """GPUTypeSerializer model options."""

        model = GPUType
Meta

Bases: Meta

GPUTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """GPUTypeSerializer model options."""

    model = GPUType

HBASerializer

Bases: FSUModelSerializer

API serializer for HBA model.

Source code in nautobot_fsus/api/serializers/fsus.py
class HBASerializer(FSUModelSerializer):
    """API serializer for HBA model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:hba-detail")
    disks = serializers.PrimaryKeyRelatedField(
        queryset=Disk.objects.all(),
        many=True,
        required=False,
        allow_null=True,
    )

    class Meta(FSUModelSerializer.Meta):
        """HBASerializer model options."""

        model = HBA

    def validate(self, data: Any):
        """Need to hide the disks field from normal validation."""
        to_validate = copy(data)

        # Need to remove the list of disks before the first validation step, otherwise the
        # model validation will complain because you can't set parent_hba on the disks in
        # this direction, that's handled in the create()/update() methods.
        _ = to_validate.pop("disks", None)

        super().validate(to_validate)

        return data

    def create(self, validated_data: Any) -> HBA:
        """Create a new HBA instance with child Disk validation."""
        # disks is optional in the POST data, set it to an empty list if it's not present
        disks = validated_data.pop("disks", [])

        try:
            with transaction.atomic():
                if disks:
                    # Validate parent device
                    validate_parent_device(disks, validated_data.get("device", None))

                    # Child disks must not have a parent HBA assigned
                    for disk in disks:
                        if disk.parent_hba is not None:
                            raise ValidationError(
                                f"Disk {disk.name} is already assigned to {disk.parent_hba.name}"
                            )

                # Create the HBA instance
                instance: HBA = HBA.objects.create(**validated_data)

                # Set the parent_hba for any specified child Disk instances
                for disk in disks:
                    disk.parent_hba = instance
                    disk.validated_save()

        except ValidationError as error:
            raise serializers.ValidationError({"disks": error.messages[0]}) from error

        return instance

    def update(self, instance: HBA, validated_data: Any) -> HBA:
        """
        Update an existing HBA instance.

        PUT requests must have all required field, PATCH requests need only the changed fields.
        When updating an HBA instance, child Disks update logic is:
        - disks not set or null, device and storage location not updated -> no changes
        - disks set and device is not set or instance device is None -> ValidationError
        - disks is an empty list -> clear parent_hba on any existing child Disks
        - disks is set, device is set or instance.device is not None and any disk.device is not
            the same as the device value or the instance.device -> ValidationError
        - disks is set, device is set or instance.device is not None -> set parent_hba to
            instance for Disks in the list, clear parent_hba for any that are currently set
            to the instance but are not in the list
        - disks not set or null and storage location set -> clear any existing child Disks
        """
        # For update operations we need to know if the disks field is present in the PUT/PATCH data,
        # as an empty list triggers clearing parent_gpubaseboard for current child Disks
        disks = validated_data.pop("disks", None)

        location = validated_data.get("location", None)
        parent_device = None if location else validated_data.get("device", instance.device)

        try:
            with transaction.atomic():
                # An empty list means we're clearing the child Disks for this HBA
                # Moving an HBA to a location means we need to clear any child Disks
                if (disks is not None and len(disks) == 0) or location is not None:
                    for disk in instance.disks.all():
                        disk.parent_hba = None
                        disk.validated_save()

                elif disks:
                    # Validate the parent device
                    validate_parent_device(disks, parent_device)

                    # Track the currently set child Disks to update properly if the list has changed
                    current_disks = set(list(instance.disks.all()))
                    new_disks = set()
                    for disk in disks:
                        # New child Disks must not have a parent HBA assigned
                        if disk not in current_disks and disk.parent_hba is not None:
                            raise ValidationError(
                                f"Disk {disk.name} is already assigned to {disk.parent_hba.name}"
                            )
                        new_disks.add(disk)

                    # Set parent_hba for newly added child Disks
                    for new_disk in new_disks.difference(current_disks):
                        new_disk.parent_hba = instance
                        new_disk.validated_save()

                    # Remove any currently assigned child Disks that are not in the updated list
                    for disk in current_disks.difference(new_disks):
                        disk.parent_hba = None
                        disk.validated_save()

                validated_instance: HBA = super().update(instance, validated_data)

        except ValidationError as error:
            raise serializers.ValidationError({"disks": error.messages[0]}) from error

        return validated_instance
Meta

Bases: Meta

HBASerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """HBASerializer model options."""

    model = HBA
create(validated_data)

Create a new HBA instance with child Disk validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def create(self, validated_data: Any) -> HBA:
    """Create a new HBA instance with child Disk validation."""
    # disks is optional in the POST data, set it to an empty list if it's not present
    disks = validated_data.pop("disks", [])

    try:
        with transaction.atomic():
            if disks:
                # Validate parent device
                validate_parent_device(disks, validated_data.get("device", None))

                # Child disks must not have a parent HBA assigned
                for disk in disks:
                    if disk.parent_hba is not None:
                        raise ValidationError(
                            f"Disk {disk.name} is already assigned to {disk.parent_hba.name}"
                        )

            # Create the HBA instance
            instance: HBA = HBA.objects.create(**validated_data)

            # Set the parent_hba for any specified child Disk instances
            for disk in disks:
                disk.parent_hba = instance
                disk.validated_save()

    except ValidationError as error:
        raise serializers.ValidationError({"disks": error.messages[0]}) from error

    return instance
update(instance, validated_data)

Update an existing HBA instance.

PUT requests must have all required field, PATCH requests need only the changed fields. When updating an HBA instance, child Disks update logic is: - disks not set or null, device and storage location not updated -> no changes - disks set and device is not set or instance device is None -> ValidationError - disks is an empty list -> clear parent_hba on any existing child Disks - disks is set, device is set or instance.device is not None and any disk.device is not the same as the device value or the instance.device -> ValidationError - disks is set, device is set or instance.device is not None -> set parent_hba to instance for Disks in the list, clear parent_hba for any that are currently set to the instance but are not in the list - disks not set or null and storage location set -> clear any existing child Disks

Source code in nautobot_fsus/api/serializers/fsus.py
def update(self, instance: HBA, validated_data: Any) -> HBA:
    """
    Update an existing HBA instance.

    PUT requests must have all required field, PATCH requests need only the changed fields.
    When updating an HBA instance, child Disks update logic is:
    - disks not set or null, device and storage location not updated -> no changes
    - disks set and device is not set or instance device is None -> ValidationError
    - disks is an empty list -> clear parent_hba on any existing child Disks
    - disks is set, device is set or instance.device is not None and any disk.device is not
        the same as the device value or the instance.device -> ValidationError
    - disks is set, device is set or instance.device is not None -> set parent_hba to
        instance for Disks in the list, clear parent_hba for any that are currently set
        to the instance but are not in the list
    - disks not set or null and storage location set -> clear any existing child Disks
    """
    # For update operations we need to know if the disks field is present in the PUT/PATCH data,
    # as an empty list triggers clearing parent_gpubaseboard for current child Disks
    disks = validated_data.pop("disks", None)

    location = validated_data.get("location", None)
    parent_device = None if location else validated_data.get("device", instance.device)

    try:
        with transaction.atomic():
            # An empty list means we're clearing the child Disks for this HBA
            # Moving an HBA to a location means we need to clear any child Disks
            if (disks is not None and len(disks) == 0) or location is not None:
                for disk in instance.disks.all():
                    disk.parent_hba = None
                    disk.validated_save()

            elif disks:
                # Validate the parent device
                validate_parent_device(disks, parent_device)

                # Track the currently set child Disks to update properly if the list has changed
                current_disks = set(list(instance.disks.all()))
                new_disks = set()
                for disk in disks:
                    # New child Disks must not have a parent HBA assigned
                    if disk not in current_disks and disk.parent_hba is not None:
                        raise ValidationError(
                            f"Disk {disk.name} is already assigned to {disk.parent_hba.name}"
                        )
                    new_disks.add(disk)

                # Set parent_hba for newly added child Disks
                for new_disk in new_disks.difference(current_disks):
                    new_disk.parent_hba = instance
                    new_disk.validated_save()

                # Remove any currently assigned child Disks that are not in the updated list
                for disk in current_disks.difference(new_disks):
                    disk.parent_hba = None
                    disk.validated_save()

            validated_instance: HBA = super().update(instance, validated_data)

    except ValidationError as error:
        raise serializers.ValidationError({"disks": error.messages[0]}) from error

    return validated_instance
validate(data)

Need to hide the disks field from normal validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def validate(self, data: Any):
    """Need to hide the disks field from normal validation."""
    to_validate = copy(data)

    # Need to remove the list of disks before the first validation step, otherwise the
    # model validation will complain because you can't set parent_hba on the disks in
    # this direction, that's handled in the create()/update() methods.
    _ = to_validate.pop("disks", None)

    super().validate(to_validate)

    return data

HBATemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for HBATemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class HBATemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for HBATemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:hbatemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """HBTemplateSerializer model options."""

        model = HBATemplate
Meta

Bases: Meta

HBTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """HBTemplateSerializer model options."""

    model = HBATemplate

HBATypeSerializer

Bases: FSUTypeModelSerializer

API serializer for HBAType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class HBATypeSerializer(FSUTypeModelSerializer):
    """API serializer for HBAType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:hbatype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """HBAType model options."""

        model = HBAType
Meta

Bases: Meta

HBAType model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """HBAType model options."""

    model = HBAType

MainboardSerializer

Bases: FSUModelSerializer

API serializer for Mainboard model.

Source code in nautobot_fsus/api/serializers/fsus.py
class MainboardSerializer(FSUModelSerializer):
    """API serializer for Mainboard model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:mainboard-detail")
    cpus = serializers.PrimaryKeyRelatedField(
        queryset=CPU.objects.all(),
        many=True,
        required=False,
        allow_null=True,
    )

    class Meta(FSUModelSerializer.Meta):
        """MainboardSerializer model options."""

        model = Mainboard

    def validate(self, data: Any):
        """Need to hide the cpus field from normal validation."""
        to_validate = copy(data)

        # Need to remove the list of cpus before the first validation step, otherwise the
        # model validation will complain because you can't set parent_mainboard on the cpus in
        # this direction, that's handled in the create()/update() methods.
        _ = to_validate.pop("cpus", None)

        super().validate(to_validate)

        return data

    def create(self, validated_data: Any) -> Mainboard:
        """Create a new Mainboard instance with child CPU validation."""
        # cpus is optional in the POST data, set it to an empty list if it's not present.
        cpus = validated_data.pop("cpus", [])

        try:
            with transaction.atomic():
                if cpus:
                    # Validate parent device
                    validate_parent_device(cpus, validated_data.get("device", None))

                    # Validate available sockets
                    mainboard_type = validated_data["fsu_type"]
                    if (
                        mainboard_type.cpu_socket_count is not None
                        and len(cpus) > mainboard_type.cpu_socket_count
                    ):
                        raise ValidationError(
                            f"Number of CPUs being added to Mainboard ({len(cpus)}) is "
                            f"greater than the number of available sockets "
                            f"({mainboard_type.cpu_socket_count})"
                        )

                    # Child CPUs must not have a parent Mainboard assigned
                    for cpu in cpus:
                        if cpu.parent_mainboard is not None:
                            raise ValidationError(
                                f"CPU {cpu.name} is already assigned "
                                f"to {cpu.parent_mainboard.name}"
                            )

                # Create the Mainboard instance
                instance: Mainboard = Mainboard.objects.create(**validated_data)

                # Set parent_mainboard for any specified child CPU instance
                for cpu in cpus:
                    cpu.parent_mainboard = instance
                    cpu.validated_save()

        except ValidationError as error:
            raise serializers.ValidationError({"cpus": error.messages[0]}) from error

        return instance

    def update(self, instance: Mainboard, validated_data: Any) -> Mainboard:
        """
        Update an existing Mainboard instance.

        PUT requests must have all required field, PATCH requests need only the changed fields.
        When updating a Mainboard instance, child CPUs update logic is:
        - cpus not set or null, device and storage location not updated -> no changes
        - cpus set and device is not set or instance device is None -> ValidationError
        - cpus is an empty list -> clear parent_mainboard on any existing child CPUs
        - cpus is set, device is set or instance.device is not None and any cpu.device is not
            the same as the device value or the instance.device -> ValidationError
        - cpus is set, device is set or instance.device is not None -> set parent_mainboard to
            instance for CPUs in the list, clear parent_mainboard for any that are currently set
            to the instance but are not in the list
        - cpus not set or null and storage location set -> clear any existing child CPUs
        """
        # For update operations we need to know if the cpus field is present in the PUT/PATCH data,
        # as an empty list triggers clearing parent_mainboard for current child CPUs
        cpus = validated_data.pop("cpus", None)

        location = validated_data.get("location", None)
        parent_device = None if location else validated_data.get("device", instance.device)

        try:
            with transaction.atomic():
                # An empty list means we're clearing the child CPUs for this Mainboard
                # Moving a Mainboard to a location means we need to clear any child CPUs
                if (cpus is not None and len(cpus) == 0) or location is not None:
                    for cpu in instance.cpus.all():
                        cpu.parent_mainboard = None
                        cpu.validated_save()

                elif cpus:
                    # Validate the parent device
                    validate_parent_device(cpus, parent_device)

                    # Validate available sockets
                    mainboard_type = instance.fsu_type
                    if (
                        mainboard_type.cpu_socket_count is not None
                        and len(cpus) > mainboard_type.cpu_socket_count
                    ):
                        raise ValidationError(
                            f"Number of CPUs being added to Mainboard ({len(cpus)}) is "
                            f"greater than the number of available sockets "
                            f"({mainboard_type.cpu_socket_count})"
                        )

                    # Track the currently set child CPUs to update properly if the list has changed
                    current_cpus = set(list(instance.cpus.all()))
                    new_cpus = set()
                    for cpu in cpus:
                        # New child CPU must not have a parent Mainboard assigned
                        if cpu not in current_cpus and cpu.parent_mainboard is not None:
                            raise ValidationError(
                                f"CPU {cpu.name} is already assigned "
                                f"to {cpu.parent_mainboard.name}"
                            )
                        new_cpus.add(cpu)

                    # Set parent_mainboard for newly added child CPUs
                    for new_cpu in new_cpus.difference(current_cpus):
                        new_cpu.parent_mainboard = instance
                        new_cpu.validated_save()

                    # Remove any currently assigned child CPUs that are not in the updated list
                    for cpu in current_cpus.difference(new_cpus):
                        cpu.parent_mainboard = None
                        cpu.validated_save()

                validated_instance: Mainboard = super().update(instance, validated_data)

        except ValidationError as error:
            raise serializers.ValidationError({"cpus": error.messages[0]}) from error

        return validated_instance
Meta

Bases: Meta

MainboardSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """MainboardSerializer model options."""

    model = Mainboard
create(validated_data)

Create a new Mainboard instance with child CPU validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def create(self, validated_data: Any) -> Mainboard:
    """Create a new Mainboard instance with child CPU validation."""
    # cpus is optional in the POST data, set it to an empty list if it's not present.
    cpus = validated_data.pop("cpus", [])

    try:
        with transaction.atomic():
            if cpus:
                # Validate parent device
                validate_parent_device(cpus, validated_data.get("device", None))

                # Validate available sockets
                mainboard_type = validated_data["fsu_type"]
                if (
                    mainboard_type.cpu_socket_count is not None
                    and len(cpus) > mainboard_type.cpu_socket_count
                ):
                    raise ValidationError(
                        f"Number of CPUs being added to Mainboard ({len(cpus)}) is "
                        f"greater than the number of available sockets "
                        f"({mainboard_type.cpu_socket_count})"
                    )

                # Child CPUs must not have a parent Mainboard assigned
                for cpu in cpus:
                    if cpu.parent_mainboard is not None:
                        raise ValidationError(
                            f"CPU {cpu.name} is already assigned "
                            f"to {cpu.parent_mainboard.name}"
                        )

            # Create the Mainboard instance
            instance: Mainboard = Mainboard.objects.create(**validated_data)

            # Set parent_mainboard for any specified child CPU instance
            for cpu in cpus:
                cpu.parent_mainboard = instance
                cpu.validated_save()

    except ValidationError as error:
        raise serializers.ValidationError({"cpus": error.messages[0]}) from error

    return instance
update(instance, validated_data)

Update an existing Mainboard instance.

PUT requests must have all required field, PATCH requests need only the changed fields. When updating a Mainboard instance, child CPUs update logic is: - cpus not set or null, device and storage location not updated -> no changes - cpus set and device is not set or instance device is None -> ValidationError - cpus is an empty list -> clear parent_mainboard on any existing child CPUs - cpus is set, device is set or instance.device is not None and any cpu.device is not the same as the device value or the instance.device -> ValidationError - cpus is set, device is set or instance.device is not None -> set parent_mainboard to instance for CPUs in the list, clear parent_mainboard for any that are currently set to the instance but are not in the list - cpus not set or null and storage location set -> clear any existing child CPUs

Source code in nautobot_fsus/api/serializers/fsus.py
def update(self, instance: Mainboard, validated_data: Any) -> Mainboard:
    """
    Update an existing Mainboard instance.

    PUT requests must have all required field, PATCH requests need only the changed fields.
    When updating a Mainboard instance, child CPUs update logic is:
    - cpus not set or null, device and storage location not updated -> no changes
    - cpus set and device is not set or instance device is None -> ValidationError
    - cpus is an empty list -> clear parent_mainboard on any existing child CPUs
    - cpus is set, device is set or instance.device is not None and any cpu.device is not
        the same as the device value or the instance.device -> ValidationError
    - cpus is set, device is set or instance.device is not None -> set parent_mainboard to
        instance for CPUs in the list, clear parent_mainboard for any that are currently set
        to the instance but are not in the list
    - cpus not set or null and storage location set -> clear any existing child CPUs
    """
    # For update operations we need to know if the cpus field is present in the PUT/PATCH data,
    # as an empty list triggers clearing parent_mainboard for current child CPUs
    cpus = validated_data.pop("cpus", None)

    location = validated_data.get("location", None)
    parent_device = None if location else validated_data.get("device", instance.device)

    try:
        with transaction.atomic():
            # An empty list means we're clearing the child CPUs for this Mainboard
            # Moving a Mainboard to a location means we need to clear any child CPUs
            if (cpus is not None and len(cpus) == 0) or location is not None:
                for cpu in instance.cpus.all():
                    cpu.parent_mainboard = None
                    cpu.validated_save()

            elif cpus:
                # Validate the parent device
                validate_parent_device(cpus, parent_device)

                # Validate available sockets
                mainboard_type = instance.fsu_type
                if (
                    mainboard_type.cpu_socket_count is not None
                    and len(cpus) > mainboard_type.cpu_socket_count
                ):
                    raise ValidationError(
                        f"Number of CPUs being added to Mainboard ({len(cpus)}) is "
                        f"greater than the number of available sockets "
                        f"({mainboard_type.cpu_socket_count})"
                    )

                # Track the currently set child CPUs to update properly if the list has changed
                current_cpus = set(list(instance.cpus.all()))
                new_cpus = set()
                for cpu in cpus:
                    # New child CPU must not have a parent Mainboard assigned
                    if cpu not in current_cpus and cpu.parent_mainboard is not None:
                        raise ValidationError(
                            f"CPU {cpu.name} is already assigned "
                            f"to {cpu.parent_mainboard.name}"
                        )
                    new_cpus.add(cpu)

                # Set parent_mainboard for newly added child CPUs
                for new_cpu in new_cpus.difference(current_cpus):
                    new_cpu.parent_mainboard = instance
                    new_cpu.validated_save()

                # Remove any currently assigned child CPUs that are not in the updated list
                for cpu in current_cpus.difference(new_cpus):
                    cpu.parent_mainboard = None
                    cpu.validated_save()

            validated_instance: Mainboard = super().update(instance, validated_data)

    except ValidationError as error:
        raise serializers.ValidationError({"cpus": error.messages[0]}) from error

    return validated_instance
validate(data)

Need to hide the cpus field from normal validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def validate(self, data: Any):
    """Need to hide the cpus field from normal validation."""
    to_validate = copy(data)

    # Need to remove the list of cpus before the first validation step, otherwise the
    # model validation will complain because you can't set parent_mainboard on the cpus in
    # this direction, that's handled in the create()/update() methods.
    _ = to_validate.pop("cpus", None)

    super().validate(to_validate)

    return data

MainboardTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for MainboardTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class MainboardTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for MainboardTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:mainboardtemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """MainboardTemplateSerializer model options."""

        model = MainboardTemplate
Meta

Bases: Meta

MainboardTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """MainboardTemplateSerializer model options."""

    model = MainboardTemplate

MainboardTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for MainboardType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class MainboardTypeSerializer(FSUTypeModelSerializer):
    """API serializer for MainboardType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:mainboardtype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """MainboardTypeSerializer model options."""

        model = MainboardType
Meta

Bases: Meta

MainboardTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """MainboardTypeSerializer model options."""

    model = MainboardType

NICSerializer

Bases: FSUModelSerializer

API serializer for NIC model.

Source code in nautobot_fsus/api/serializers/fsus.py
class NICSerializer(FSUModelSerializer):
    """API serializer for NIC model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:nic-detail")
    interfaces = serializers.PrimaryKeyRelatedField(
        queryset=Interface.objects.all(),
        many=True,
        required=False,
        allow_null=True,
    )

    class Meta(FSUModelSerializer.Meta):
        """NICSerializer model options."""

        model = NIC

    def create(self, validated_data: Any) -> NIC:
        """Create a new NIC instance with child Interface validation."""
        # interfaces field is optional in the POST data, set it to an empty list if it's not present
        interfaces = validated_data.pop("interfaces", [])

        try:
            with transaction.atomic():
                if interfaces:
                    # Validate the parent device
                    validate_parent_device(interfaces, validated_data.get("device", None))

                    # Validate available connections
                    nic_type = validated_data["fsu_type"]
                    if (
                        nic_type.interface_count is not None
                        and len(interfaces) > nic_type.interface_count
                    ):
                        raise ValidationError(
                            f"Number of Interfaces being added to NIC ({len(interfaces)}) is "
                            f"greater than the number of available connections "
                            f"({nic_type.interface_count})"
                        )

                    # Child Interfaces must not have a parent NIC assigned
                    for interface in interfaces:
                        if interface.parent_nic.first() is not None:
                            raise ValidationError(
                                f"interface {interface.name} is already assigned to "
                                f"{interface.parent_nic.first().name}"
                            )

                # Create the NIC instance
                instance: NIC = NIC.objects.create(**validated_data)

                # Add the child interfaces
                instance.interfaces.set(interfaces)

        except ValidationError as error:
            raise serializers.ValidationError({"interfaces": error.messages[0]}) from error

        return instance

    def update(self, instance: NIC, validated_data: Any) -> NIC:
        """
        Update an existing NIC instance.

        PUT requests must have all required field, PATCH requests need only the changed fields.
        When updating a NIC instance, child Interface update logic is:
        - interfaces not set or null, device and storage location not updated -> no changes
        - interfaces set and device is not set or instance device is None -> ValidationError
        - interfaces is an empty list -> clear parent_nic on any existing child Interfaces
        - interfaces is set, device is set or instance.device is not None and any interfaces.device
            is not the same as the device value or the instance.device -> ValidationError
        - interfaces is set, device is set or instance.device is not None -> set parent_nic to
            instance for Interfaces in the list, clear parent_nic for any that are currently set
            to the instance but are not in the list
        - interfaces not set or null and storage location set -> clear any existing child Interfaces
        """
        # For update operations we need to know if the interfaces field is present in the
        # PUT/PATCH data, as an empty list triggers clearing parent_nic for current child Interfaces
        interfaces = validated_data.pop("interfaces", None)

        location = validated_data.get("location", None)
        parent_device = None if location else validated_data.get("device", instance.device)

        try:
            with transaction.atomic():
                # An empty list means we're clearing the child Interfaces for this NIC
                # Moving a NIC to a location means we need to clear any child Interfaces
                if (interfaces is not None and len(interfaces) == 0) or location is not None:
                    instance.interfaces.clear()

                elif interfaces:
                    # Validate the parent device
                    validate_parent_device(interfaces, parent_device)

                    # Validate available slots
                    nic_type = instance.fsu_type
                    if (
                        nic_type.interface_count is not None
                        and len(interfaces) > nic_type.interface_count
                    ):
                        raise ValidationError(
                            f"Number of Interfaces being added to NIC ({len(interfaces)}) is "
                            f"greater than the number of available connections "
                            f"({nic_type.interface_count})"
                        )

                    # New child Interface must not have a parent NIC assigned
                    current_interfaces = set(list(instance.interfaces.all()))
                    for interface in interfaces:
                        if (
                            interface not in current_interfaces
                            and interface.parent_nic.first() is not None
                        ):
                            raise ValidationError(
                                f"interface {interface.name} is already assigned to "
                                f"{interface.parent_nic.first().name}"
                            )

                    # Set the new interface list on the NIC
                    instance.interfaces.set(interfaces)

                validated_instance: NIC = super().update(instance, validated_data)

        except ValidationError as error:
            raise serializers.ValidationError({"interfaces": error.messages[0]}) from error

        return validated_instance
Meta

Bases: Meta

NICSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """NICSerializer model options."""

    model = NIC
create(validated_data)

Create a new NIC instance with child Interface validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def create(self, validated_data: Any) -> NIC:
    """Create a new NIC instance with child Interface validation."""
    # interfaces field is optional in the POST data, set it to an empty list if it's not present
    interfaces = validated_data.pop("interfaces", [])

    try:
        with transaction.atomic():
            if interfaces:
                # Validate the parent device
                validate_parent_device(interfaces, validated_data.get("device", None))

                # Validate available connections
                nic_type = validated_data["fsu_type"]
                if (
                    nic_type.interface_count is not None
                    and len(interfaces) > nic_type.interface_count
                ):
                    raise ValidationError(
                        f"Number of Interfaces being added to NIC ({len(interfaces)}) is "
                        f"greater than the number of available connections "
                        f"({nic_type.interface_count})"
                    )

                # Child Interfaces must not have a parent NIC assigned
                for interface in interfaces:
                    if interface.parent_nic.first() is not None:
                        raise ValidationError(
                            f"interface {interface.name} is already assigned to "
                            f"{interface.parent_nic.first().name}"
                        )

            # Create the NIC instance
            instance: NIC = NIC.objects.create(**validated_data)

            # Add the child interfaces
            instance.interfaces.set(interfaces)

    except ValidationError as error:
        raise serializers.ValidationError({"interfaces": error.messages[0]}) from error

    return instance
update(instance, validated_data)

Update an existing NIC instance.

PUT requests must have all required field, PATCH requests need only the changed fields. When updating a NIC instance, child Interface update logic is: - interfaces not set or null, device and storage location not updated -> no changes - interfaces set and device is not set or instance device is None -> ValidationError - interfaces is an empty list -> clear parent_nic on any existing child Interfaces - interfaces is set, device is set or instance.device is not None and any interfaces.device is not the same as the device value or the instance.device -> ValidationError - interfaces is set, device is set or instance.device is not None -> set parent_nic to instance for Interfaces in the list, clear parent_nic for any that are currently set to the instance but are not in the list - interfaces not set or null and storage location set -> clear any existing child Interfaces

Source code in nautobot_fsus/api/serializers/fsus.py
def update(self, instance: NIC, validated_data: Any) -> NIC:
    """
    Update an existing NIC instance.

    PUT requests must have all required field, PATCH requests need only the changed fields.
    When updating a NIC instance, child Interface update logic is:
    - interfaces not set or null, device and storage location not updated -> no changes
    - interfaces set and device is not set or instance device is None -> ValidationError
    - interfaces is an empty list -> clear parent_nic on any existing child Interfaces
    - interfaces is set, device is set or instance.device is not None and any interfaces.device
        is not the same as the device value or the instance.device -> ValidationError
    - interfaces is set, device is set or instance.device is not None -> set parent_nic to
        instance for Interfaces in the list, clear parent_nic for any that are currently set
        to the instance but are not in the list
    - interfaces not set or null and storage location set -> clear any existing child Interfaces
    """
    # For update operations we need to know if the interfaces field is present in the
    # PUT/PATCH data, as an empty list triggers clearing parent_nic for current child Interfaces
    interfaces = validated_data.pop("interfaces", None)

    location = validated_data.get("location", None)
    parent_device = None if location else validated_data.get("device", instance.device)

    try:
        with transaction.atomic():
            # An empty list means we're clearing the child Interfaces for this NIC
            # Moving a NIC to a location means we need to clear any child Interfaces
            if (interfaces is not None and len(interfaces) == 0) or location is not None:
                instance.interfaces.clear()

            elif interfaces:
                # Validate the parent device
                validate_parent_device(interfaces, parent_device)

                # Validate available slots
                nic_type = instance.fsu_type
                if (
                    nic_type.interface_count is not None
                    and len(interfaces) > nic_type.interface_count
                ):
                    raise ValidationError(
                        f"Number of Interfaces being added to NIC ({len(interfaces)}) is "
                        f"greater than the number of available connections "
                        f"({nic_type.interface_count})"
                    )

                # New child Interface must not have a parent NIC assigned
                current_interfaces = set(list(instance.interfaces.all()))
                for interface in interfaces:
                    if (
                        interface not in current_interfaces
                        and interface.parent_nic.first() is not None
                    ):
                        raise ValidationError(
                            f"interface {interface.name} is already assigned to "
                            f"{interface.parent_nic.first().name}"
                        )

                # Set the new interface list on the NIC
                instance.interfaces.set(interfaces)

            validated_instance: NIC = super().update(instance, validated_data)

    except ValidationError as error:
        raise serializers.ValidationError({"interfaces": error.messages[0]}) from error

    return validated_instance

NICTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for NICTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class NICTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for NICTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:nictemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """NICTemplateSerializer model options."""

        model = NICTemplate
Meta

Bases: Meta

NICTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """NICTemplateSerializer model options."""

    model = NICTemplate

NICTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for NICType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class NICTypeSerializer(FSUTypeModelSerializer):
    """API serializer for NICType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:nictype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """NICTypeSerializer model options."""

        model = NICType
Meta

Bases: Meta

NICTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """NICTypeSerializer model options."""

    model = NICType

OtherFSUSerializer

Bases: FSUModelSerializer

API serializer for Other FSU model.

Source code in nautobot_fsus/api/serializers/fsus.py
class OtherFSUSerializer(FSUModelSerializer):
    """API serializer for Other FSU model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:otherfsu-detail")

    class Meta(FSUModelSerializer.Meta):
        """OtherFSUSerializer model options."""

        model = OtherFSU
Meta

Bases: Meta

OtherFSUSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """OtherFSUSerializer model options."""

    model = OtherFSU

OtherFSUTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for OtherFSUTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class OtherFSUTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for OtherFSUTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:otherfsutemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """OtherFSUTemplateSerializer model options."""

        model = OtherFSUTemplate
Meta

Bases: Meta

OtherFSUTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """OtherFSUTemplateSerializer model options."""

    model = OtherFSUTemplate

OtherFSUTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for OtherFSUType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class OtherFSUTypeSerializer(FSUTypeModelSerializer):
    """API serializer for OtherFSUType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:otherfsutype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """OtherFSUTypeSerializer model options."""

        model = OtherFSUType
Meta

Bases: Meta

OtherFSUTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """OtherFSUTypeSerializer model options."""

    model = OtherFSUType

PSUSerializer

Bases: FSUModelSerializer

API serializer for PSU model.

Source code in nautobot_fsus/api/serializers/fsus.py
class PSUSerializer(FSUModelSerializer):
    """API serializer for PSU model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:psu-detail")
    power_ports = serializers.PrimaryKeyRelatedField(
        queryset=PowerPort.objects.all(),
        many=True,
        required=False,
        allow_null=True,
    )

    class Meta(FSUModelSerializer.Meta):
        """PSUSerializer model options."""

        model = PSU

    def create(self, validated_data: Any) -> PSU:
        """Create a new PSU instance with child PowerPort validation."""
        # power_ports field is optional in the POST data, set it to an empty list if it's not present
        power_ports = validated_data.pop("power_ports", [])

        try:
            with transaction.atomic():
                if power_ports:
                    # Validate the parent device
                    validate_parent_device(power_ports, validated_data.get("device", None))

                    # Child PowerPorts must not have a parent PSU assigned
                    for power_port in power_ports:
                        if power_port.parent_psu.first() is not None:
                            raise ValidationError(
                                f"power port {power_port.name} is already assigned to "
                                f"{power_port.parent_psu.first().name}"
                            )

                # Create the PSU instance
                instance: PSU = PSU.objects.create(**validated_data)

                # Add the child interfaces
                instance.power_ports.set(power_ports)

        except ValidationError as error:
            raise serializers.ValidationError({"power_ports": error.messages[0]}) from error

        return instance

    def update(self, instance: PSU, validated_data: Any) -> PSU:
        """
        Update an existing PSU instance.

        PUT requests must have all required field, PATCH requests need only the changed fields.
        When updating a PSU instance, child PowerPort update logic is:
        - power_ports not set or null, device and storage location not updated -> no changes
        - power_ports set and device is not set or instance device is None -> ValidationError
        - power_ports is an empty list -> clear power_ports on the instance
        - power_ports is set, device is set or instance.device is not None and any
            power_ports.device is not the same as the device value or the
            instance.device -> ValidationError
        - power_ports is set, device is set or instance.device is not None -> set power_ports
            on the instance to the new list.
        - power_ports not set or null and storage location set -> clear any existing child PowerPorts
        """
        # For update operations we need to know if the power_ports field is present in the
        # PUT/PATCH data, as an empty list triggers clearing parent_psu for current child PowerPorts
        power_ports = validated_data.pop("power_ports", None)

        location = validated_data.get("location", None)
        parent_device = None if location else validated_data.get("device", instance.device)

        try:
            with transaction.atomic():
                # An empty list means we're clearing the child PowerPorts for this PSU
                # Moving a PSU to a location means we need to clear any child PowerPorts
                if (power_ports is not None and len(power_ports) == 0) or location is not None:
                    instance.power_ports.clear()

                elif power_ports:
                    # Validate the parent device
                    validate_parent_device(power_ports, parent_device)

                    # New child PowerPorts must not have a parent PSU assigned
                    current_power_ports = set(list(instance.power_ports.all()))
                    for power_port in power_ports:
                        if (
                            power_port not in current_power_ports
                            and power_port.parent_psu.first() is not None
                        ):
                            raise ValidationError(
                                f"Power Port {power_port.name} is already assigned to "
                                f"{power_port.parent_psu.first().name}"
                            )

                    # Set the new interface list on the NIC
                    instance.power_ports.set(power_ports)

                validated_instance: PSU = super().update(instance, validated_data)

        except ValidationError as error:
            raise serializers.ValidationError({"power_ports": error.messages[0]}) from error

        return validated_instance
Meta

Bases: Meta

PSUSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """PSUSerializer model options."""

    model = PSU
create(validated_data)

Create a new PSU instance with child PowerPort validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def create(self, validated_data: Any) -> PSU:
    """Create a new PSU instance with child PowerPort validation."""
    # power_ports field is optional in the POST data, set it to an empty list if it's not present
    power_ports = validated_data.pop("power_ports", [])

    try:
        with transaction.atomic():
            if power_ports:
                # Validate the parent device
                validate_parent_device(power_ports, validated_data.get("device", None))

                # Child PowerPorts must not have a parent PSU assigned
                for power_port in power_ports:
                    if power_port.parent_psu.first() is not None:
                        raise ValidationError(
                            f"power port {power_port.name} is already assigned to "
                            f"{power_port.parent_psu.first().name}"
                        )

            # Create the PSU instance
            instance: PSU = PSU.objects.create(**validated_data)

            # Add the child interfaces
            instance.power_ports.set(power_ports)

    except ValidationError as error:
        raise serializers.ValidationError({"power_ports": error.messages[0]}) from error

    return instance
update(instance, validated_data)

Update an existing PSU instance.

PUT requests must have all required field, PATCH requests need only the changed fields. When updating a PSU instance, child PowerPort update logic is: - power_ports not set or null, device and storage location not updated -> no changes - power_ports set and device is not set or instance device is None -> ValidationError - power_ports is an empty list -> clear power_ports on the instance - power_ports is set, device is set or instance.device is not None and any power_ports.device is not the same as the device value or the instance.device -> ValidationError - power_ports is set, device is set or instance.device is not None -> set power_ports on the instance to the new list. - power_ports not set or null and storage location set -> clear any existing child PowerPorts

Source code in nautobot_fsus/api/serializers/fsus.py
def update(self, instance: PSU, validated_data: Any) -> PSU:
    """
    Update an existing PSU instance.

    PUT requests must have all required field, PATCH requests need only the changed fields.
    When updating a PSU instance, child PowerPort update logic is:
    - power_ports not set or null, device and storage location not updated -> no changes
    - power_ports set and device is not set or instance device is None -> ValidationError
    - power_ports is an empty list -> clear power_ports on the instance
    - power_ports is set, device is set or instance.device is not None and any
        power_ports.device is not the same as the device value or the
        instance.device -> ValidationError
    - power_ports is set, device is set or instance.device is not None -> set power_ports
        on the instance to the new list.
    - power_ports not set or null and storage location set -> clear any existing child PowerPorts
    """
    # For update operations we need to know if the power_ports field is present in the
    # PUT/PATCH data, as an empty list triggers clearing parent_psu for current child PowerPorts
    power_ports = validated_data.pop("power_ports", None)

    location = validated_data.get("location", None)
    parent_device = None if location else validated_data.get("device", instance.device)

    try:
        with transaction.atomic():
            # An empty list means we're clearing the child PowerPorts for this PSU
            # Moving a PSU to a location means we need to clear any child PowerPorts
            if (power_ports is not None and len(power_ports) == 0) or location is not None:
                instance.power_ports.clear()

            elif power_ports:
                # Validate the parent device
                validate_parent_device(power_ports, parent_device)

                # New child PowerPorts must not have a parent PSU assigned
                current_power_ports = set(list(instance.power_ports.all()))
                for power_port in power_ports:
                    if (
                        power_port not in current_power_ports
                        and power_port.parent_psu.first() is not None
                    ):
                        raise ValidationError(
                            f"Power Port {power_port.name} is already assigned to "
                            f"{power_port.parent_psu.first().name}"
                        )

                # Set the new interface list on the NIC
                instance.power_ports.set(power_ports)

            validated_instance: PSU = super().update(instance, validated_data)

    except ValidationError as error:
        raise serializers.ValidationError({"power_ports": error.messages[0]}) from error

    return validated_instance

PSUTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for PSUTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class PSUTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for PSUTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:psutemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """PSUTemplateSerializer model options."""

        model = PSUTemplate
Meta

Bases: Meta

PSUTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """PSUTemplateSerializer model options."""

    model = PSUTemplate

PSUTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for PSUType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class PSUTypeSerializer(FSUTypeModelSerializer):
    """API serializer for PSUType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:psutype-detail"
    )

    feed_type = ChoiceField(choices=choices.PSUFeedType)

    class Meta(FSUTypeModelSerializer.Meta):
        """PSUTypeSerializer model options."""

        model = PSUType
Meta

Bases: Meta

PSUTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """PSUTypeSerializer model options."""

    model = PSUType

RAMModuleSerializer

Bases: FSUModelSerializer

API serializer for RAM Module model.

Source code in nautobot_fsus/api/serializers/fsus.py
class RAMModuleSerializer(FSUModelSerializer):
    """API serializer for RAM Module model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:rammodule-detail")

    class Meta(FSUModelSerializer.Meta):
        """RAMModuleSerializer model options."""

        model = RAMModule
Meta

Bases: Meta

RAMModuleSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """RAMModuleSerializer model options."""

    model = RAMModule

RAMModuleTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for RAMModuleTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class RAMModuleTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for RAMModuleTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:rammoduletemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """RAMModuleTemplateSerializer model options."""

        model = RAMModuleTemplate
Meta

Bases: Meta

RAMModuleTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """RAMModuleTemplateSerializer model options."""

    model = RAMModuleTemplate

RAMModuleTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for RAMModuleType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class RAMModuleTypeSerializer(FSUTypeModelSerializer):
    """API serializer for RAMModuleType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:rammoduletype-detail"
    )

    module_type = ChoiceField(choices=choices.MemoryModuleTypes)
    technology = ChoiceField(choices=choices.MemoryTechnologies)

    class Meta(FSUTypeModelSerializer.Meta):
        """RAMModuleTypeSerializer model options."""

        model = RAMModuleType
Meta

Bases: Meta

RAMModuleTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """RAMModuleTypeSerializer model options."""

    model = RAMModuleType

fsu_templates

Model serializers for FSU template API endpoints.

CPUTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for CPUTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class CPUTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for CPUTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:cputemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """CPUTemplateSerializer model options."""

        model = CPUTemplate
Meta

Bases: Meta

CPUTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """CPUTemplateSerializer model options."""

    model = CPUTemplate
DiskTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for DiskTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class DiskTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for DiskTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:disktemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """DiskTemplateSerializer model options."""

        model = DiskTemplate
Meta

Bases: Meta

DiskTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """DiskTemplateSerializer model options."""

    model = DiskTemplate
FanTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for FanTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class FanTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for FanTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:fantemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """FanTemplateSerializer model options."""

        model = FanTemplate
Meta

Bases: Meta

FanTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """FanTemplateSerializer model options."""

    model = FanTemplate
GPUBaseboardTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for GPUBaseboardTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class GPUBaseboardTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for GPUBaseboardTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:gpubaseboardtemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """GPUBaseboardTemplateSerializer model options."""

        model = GPUBaseboardTemplate
Meta

Bases: Meta

GPUBaseboardTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """GPUBaseboardTemplateSerializer model options."""

    model = GPUBaseboardTemplate
GPUTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for GPUTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class GPUTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for GPUTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:gputemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """GPUTemplateSerializer model options."""

        model = GPUTemplate
Meta

Bases: Meta

GPUTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """GPUTemplateSerializer model options."""

    model = GPUTemplate
HBATemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for HBATemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class HBATemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for HBATemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:hbatemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """HBTemplateSerializer model options."""

        model = HBATemplate
Meta

Bases: Meta

HBTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """HBTemplateSerializer model options."""

    model = HBATemplate
MainboardTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for MainboardTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class MainboardTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for MainboardTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:mainboardtemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """MainboardTemplateSerializer model options."""

        model = MainboardTemplate
Meta

Bases: Meta

MainboardTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """MainboardTemplateSerializer model options."""

    model = MainboardTemplate
NICTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for NICTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class NICTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for NICTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:nictemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """NICTemplateSerializer model options."""

        model = NICTemplate
Meta

Bases: Meta

NICTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """NICTemplateSerializer model options."""

    model = NICTemplate
OtherFSUTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for OtherFSUTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class OtherFSUTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for OtherFSUTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:otherfsutemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """OtherFSUTemplateSerializer model options."""

        model = OtherFSUTemplate
Meta

Bases: Meta

OtherFSUTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """OtherFSUTemplateSerializer model options."""

    model = OtherFSUTemplate
PSUTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for PSUTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class PSUTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for PSUTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:psutemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """PSUTemplateSerializer model options."""

        model = PSUTemplate
Meta

Bases: Meta

PSUTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """PSUTemplateSerializer model options."""

    model = PSUTemplate
RAMModuleTemplateSerializer

Bases: FSUTemplateModelSerializer

API serializer for RAMModuleTemplate model.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class RAMModuleTemplateSerializer(FSUTemplateModelSerializer):
    """API serializer for RAMModuleTemplate model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:rammoduletemplate-detail"
    )

    class Meta(FSUTemplateModelSerializer.Meta):
        """RAMModuleTemplateSerializer model options."""

        model = RAMModuleTemplate
Meta

Bases: Meta

RAMModuleTemplateSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_templates.py
class Meta(FSUTemplateModelSerializer.Meta):
    """RAMModuleTemplateSerializer model options."""

    model = RAMModuleTemplate

fsu_types

Model serializers for FSU type API endpoints.

CPUTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for CPUType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class CPUTypeSerializer(FSUTypeModelSerializer):
    """API serializer for CPUType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:cputype-detail"
    )

    architecture = ChoiceField(choices=choices.CPUArchitectures)

    class Meta(FSUTypeModelSerializer.Meta):
        """CPUTypeSerializer model options."""

        model = CPUType
Meta

Bases: Meta

CPUTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """CPUTypeSerializer model options."""

    model = CPUType
DiskTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for DiskType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class DiskTypeSerializer(FSUTypeModelSerializer):
    """API serializer for DiskType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:disktype-detail"
    )

    disk_type = ChoiceField(choices=choices.DiskTypes)

    class Meta(FSUTypeModelSerializer.Meta):
        """DiskTypeSerializer model options."""

        model = DiskType
Meta

Bases: Meta

DiskTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """DiskTypeSerializer model options."""

    model = DiskType
FanTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for FanType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class FanTypeSerializer(FSUTypeModelSerializer):
    """API serializer for FanType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:fantype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """FanTypeSerializer model options."""

        model = FanType
Meta

Bases: Meta

FanTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """FanTypeSerializer model options."""

    model = FanType
GPUBaseboardTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for GPUBaseboardType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class GPUBaseboardTypeSerializer(FSUTypeModelSerializer):
    """API serializer for GPUBaseboardType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:gpubaseboardtype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """GPUBaseboardTypeSerializer model options."""

        model = GPUBaseboardType
Meta

Bases: Meta

GPUBaseboardTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """GPUBaseboardTypeSerializer model options."""

    model = GPUBaseboardType
GPUTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for GPUType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class GPUTypeSerializer(FSUTypeModelSerializer):
    """API serializer for GPUType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:gputype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """GPUTypeSerializer model options."""

        model = GPUType
Meta

Bases: Meta

GPUTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """GPUTypeSerializer model options."""

    model = GPUType
HBATypeSerializer

Bases: FSUTypeModelSerializer

API serializer for HBAType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class HBATypeSerializer(FSUTypeModelSerializer):
    """API serializer for HBAType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:hbatype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """HBAType model options."""

        model = HBAType
Meta

Bases: Meta

HBAType model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """HBAType model options."""

    model = HBAType
MainboardTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for MainboardType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class MainboardTypeSerializer(FSUTypeModelSerializer):
    """API serializer for MainboardType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:mainboardtype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """MainboardTypeSerializer model options."""

        model = MainboardType
Meta

Bases: Meta

MainboardTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """MainboardTypeSerializer model options."""

    model = MainboardType
NICTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for NICType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class NICTypeSerializer(FSUTypeModelSerializer):
    """API serializer for NICType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:nictype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """NICTypeSerializer model options."""

        model = NICType
Meta

Bases: Meta

NICTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """NICTypeSerializer model options."""

    model = NICType
OtherFSUTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for OtherFSUType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class OtherFSUTypeSerializer(FSUTypeModelSerializer):
    """API serializer for OtherFSUType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:otherfsutype-detail"
    )

    class Meta(FSUTypeModelSerializer.Meta):
        """OtherFSUTypeSerializer model options."""

        model = OtherFSUType
Meta

Bases: Meta

OtherFSUTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """OtherFSUTypeSerializer model options."""

    model = OtherFSUType
PSUTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for PSUType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class PSUTypeSerializer(FSUTypeModelSerializer):
    """API serializer for PSUType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:psutype-detail"
    )

    feed_type = ChoiceField(choices=choices.PSUFeedType)

    class Meta(FSUTypeModelSerializer.Meta):
        """PSUTypeSerializer model options."""

        model = PSUType
Meta

Bases: Meta

PSUTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """PSUTypeSerializer model options."""

    model = PSUType
RAMModuleTypeSerializer

Bases: FSUTypeModelSerializer

API serializer for RAMModuleType model.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class RAMModuleTypeSerializer(FSUTypeModelSerializer):
    """API serializer for RAMModuleType model."""

    url = serializers.HyperlinkedIdentityField(
        view_name="plugins-api:nautobot_fsus-api:rammoduletype-detail"
    )

    module_type = ChoiceField(choices=choices.MemoryModuleTypes)
    technology = ChoiceField(choices=choices.MemoryTechnologies)

    class Meta(FSUTypeModelSerializer.Meta):
        """RAMModuleTypeSerializer model options."""

        model = RAMModuleType
Meta

Bases: Meta

RAMModuleTypeSerializer model options.

Source code in nautobot_fsus/api/serializers/fsu_types.py
class Meta(FSUTypeModelSerializer.Meta):
    """RAMModuleTypeSerializer model options."""

    model = RAMModuleType

fsus

Model serializers for FSU API endpoints.

CPUSerializer

Bases: FSUModelSerializer

API serializer for CPU model.

Source code in nautobot_fsus/api/serializers/fsus.py
class CPUSerializer(FSUModelSerializer):
    """API serializer for CPU model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:cpu-detail")

    class Meta(FSUModelSerializer.Meta):
        """CPUserializer model options."""

        model = CPU
Meta

Bases: Meta

CPUserializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """CPUserializer model options."""

    model = CPU
DiskSerializer

Bases: FSUModelSerializer

API serializer for Disk model.

Source code in nautobot_fsus/api/serializers/fsus.py
class DiskSerializer(FSUModelSerializer):
    """API serializer for Disk model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:disk-detail")

    class Meta(FSUModelSerializer.Meta):
        """DiskSerializer model options."""

        model = Disk
Meta

Bases: Meta

DiskSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """DiskSerializer model options."""

    model = Disk
FanSerializer

Bases: FSUModelSerializer

API serializer for Fan model.

Source code in nautobot_fsus/api/serializers/fsus.py
class FanSerializer(FSUModelSerializer):
    """API serializer for Fan model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:fan-detail")

    class Meta(FSUModelSerializer.Meta):
        """FanSerializer model options."""

        model = Fan
Meta

Bases: Meta

FanSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """FanSerializer model options."""

    model = Fan
GPUBaseboardSerializer

Bases: FSUModelSerializer

API serializer for GPUBaseboard model.

Source code in nautobot_fsus/api/serializers/fsus.py
class GPUBaseboardSerializer(FSUModelSerializer):
    """API serializer for GPUBaseboard model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:gpubaseboard-detail")
    gpus = serializers.PrimaryKeyRelatedField(
        queryset=GPU.objects.all(),
        many=True,
        required=False,
        allow_null=True,
    )

    class Meta(FSUModelSerializer.Meta):
        """GPUBaseboardSerializer model options."""

        model = GPUBaseboard

    def validate(self, data: Any):
        """Need to hide the gpus field from normal validation."""
        to_validate = copy(data)

        # Need to remove the list of gpus before the first validation step, otherwise the
        # model validation will complain because you can't set parent_gpubaseboard on the gpus in
        # this direction, that's handled in the create()/update() methods.
        _ = to_validate.pop("gpus", None)

        super().validate(to_validate)

        return data

    def create(self, validated_data: Any) -> GPUBaseboard:
        """Create a new GPUBaseboard instance with child GPU validation."""
        # gpus is optional in the POST data, set it to an empty list if it's not present.
        gpus = validated_data.pop("gpus", [])

        try:
            with transaction.atomic():
                if gpus:
                    # Validate parent device
                    validate_parent_device(gpus, validated_data.get("device", None))

                    # Validate available slots
                    baseboard_type = validated_data["fsu_type"]
                    if (
                        baseboard_type.slot_count is not None
                        and len(gpus) > baseboard_type.slot_count
                    ):
                        raise ValidationError(
                            f"Number of GPUs being added to Baseboard ({len(gpus)}) is "
                            f"greater than the number of available slots "
                            f"({baseboard_type.slot_count})"
                        )

                    # Child GPUs must not have a parent GPU Baseboard assigned
                    for gpu in gpus:
                        if gpu.parent_gpubaseboard is not None:
                            raise ValidationError(
                                f"GPU {gpu.name} is already assigned to "
                                f"{gpu.parent_gpubaseboard.name}"
                            )

                # Create the GPUBaseboard instance
                instance: GPUBaseboard = GPUBaseboard.objects.create(**validated_data)

                # Set parent_gpubaseboard for any specified child GPU instances
                for gpu in gpus:
                    gpu.parent_gpubaseboard = instance
                    gpu.validated_save()

        except ValidationError as error:
            raise serializers.ValidationError({"gpus": error.messages[0]}) from error

        return instance

    def update(self, instance: GPUBaseboard, validated_data: Any) -> GPUBaseboard:
        """
        Update an existing GPUBaseboard instance.

        PUT requests must have all required field, PATCH requests need only the changed fields.
        When updating a GPUBaseboard instance, child GPUs update logic is:
        - gpus not set or null, device and storage location not updated -> no changes
        - gpus set and device is not set or instance device is None -> ValidationError
        - gpus is an empty list -> clear parent_gpubaseboard on any existing child GPUs
        - gpus is set, device is set or instance.device is not None and any gpu.device is not
            the same as the device value or the instance.device -> ValidationError
        - gpus is set, device is set or instance.device is not None -> set parent_gpubaseboard to
            instance for GPUs in the list, clear parent_gpubaseboard for any that are currently set
            to the instance but are not in the list
        - gpus not set or null and storage location set -> clear any existing child GPUs
        """
        # For update operations we need to know if the gpus field is present in the PUT/PATCH data,
        # as an empty list triggers clearing parent_gpubaseboard for current child GPUs
        gpus = validated_data.pop("gpus", None)

        location = validated_data.get("location", None)
        parent_device = None if location else validated_data.get("device", instance.device)

        try:
            with transaction.atomic():
                # An empty list means we're clearing the child GPUs for this GPUBasebaord
                # Moving a GPUBaseboard to a location means we need to clear any child GPUs
                if (gpus is not None and len(gpus) == 0) or location is not None:
                    for gpu in instance.gpus.all():
                        gpu.parent_gpubaseboard = None
                        gpu.validated_save()

                elif gpus:
                    # Validate the parent device
                    validate_parent_device(gpus, parent_device)

                    # Validate available slots
                    baseboard_type = instance.fsu_type
                    if (
                        baseboard_type.slot_count is not None
                        and len(gpus) > baseboard_type.slot_count
                    ):
                        raise ValidationError(
                            f"Number of GPUs being added to Baseboard ({len(gpus)}) is greater "
                            f"than the number of available slots ({baseboard_type.slot_count})"
                        )

                    # Track the currently set child GPUs to update properly
                    # if the list has changed
                    current_gpus = set(list(instance.gpus.all()))
                    new_gpus = set()
                    for gpu in gpus:
                        # New child GPUs must not have a parent GPUBaseboard assigned
                        if gpu not in current_gpus and gpu.parent_gpubaseboard is not None:
                            raise ValidationError(
                                f"GPU {gpu.name} is already assigned to "
                                f"{gpu.parent_gpubaseboard.name}"
                            )
                        new_gpus.add(gpu)

                    # Set parent_gpubaseboard for newly added child GPUs
                    for new_gpu in new_gpus.difference(current_gpus):
                        new_gpu.parent_gpubaseboard = instance
                        new_gpu.validated_save()

                    # Remove any currently assigned child GPUs that are not in the updated list
                    for gpu in current_gpus.difference(new_gpus):
                        gpu.parent_gpubaseboard = None
                        gpu.validated_save()

                validated_instance: GPUBaseboard = super().update(instance, validated_data)

        except ValidationError as error:
            raise serializers.ValidationError({"gpus": error.messages[0]}) from error

        return validated_instance
Meta

Bases: Meta

GPUBaseboardSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """GPUBaseboardSerializer model options."""

    model = GPUBaseboard
create(validated_data)

Create a new GPUBaseboard instance with child GPU validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def create(self, validated_data: Any) -> GPUBaseboard:
    """Create a new GPUBaseboard instance with child GPU validation."""
    # gpus is optional in the POST data, set it to an empty list if it's not present.
    gpus = validated_data.pop("gpus", [])

    try:
        with transaction.atomic():
            if gpus:
                # Validate parent device
                validate_parent_device(gpus, validated_data.get("device", None))

                # Validate available slots
                baseboard_type = validated_data["fsu_type"]
                if (
                    baseboard_type.slot_count is not None
                    and len(gpus) > baseboard_type.slot_count
                ):
                    raise ValidationError(
                        f"Number of GPUs being added to Baseboard ({len(gpus)}) is "
                        f"greater than the number of available slots "
                        f"({baseboard_type.slot_count})"
                    )

                # Child GPUs must not have a parent GPU Baseboard assigned
                for gpu in gpus:
                    if gpu.parent_gpubaseboard is not None:
                        raise ValidationError(
                            f"GPU {gpu.name} is already assigned to "
                            f"{gpu.parent_gpubaseboard.name}"
                        )

            # Create the GPUBaseboard instance
            instance: GPUBaseboard = GPUBaseboard.objects.create(**validated_data)

            # Set parent_gpubaseboard for any specified child GPU instances
            for gpu in gpus:
                gpu.parent_gpubaseboard = instance
                gpu.validated_save()

    except ValidationError as error:
        raise serializers.ValidationError({"gpus": error.messages[0]}) from error

    return instance
update(instance, validated_data)

Update an existing GPUBaseboard instance.

PUT requests must have all required field, PATCH requests need only the changed fields. When updating a GPUBaseboard instance, child GPUs update logic is: - gpus not set or null, device and storage location not updated -> no changes - gpus set and device is not set or instance device is None -> ValidationError - gpus is an empty list -> clear parent_gpubaseboard on any existing child GPUs - gpus is set, device is set or instance.device is not None and any gpu.device is not the same as the device value or the instance.device -> ValidationError - gpus is set, device is set or instance.device is not None -> set parent_gpubaseboard to instance for GPUs in the list, clear parent_gpubaseboard for any that are currently set to the instance but are not in the list - gpus not set or null and storage location set -> clear any existing child GPUs

Source code in nautobot_fsus/api/serializers/fsus.py
def update(self, instance: GPUBaseboard, validated_data: Any) -> GPUBaseboard:
    """
    Update an existing GPUBaseboard instance.

    PUT requests must have all required field, PATCH requests need only the changed fields.
    When updating a GPUBaseboard instance, child GPUs update logic is:
    - gpus not set or null, device and storage location not updated -> no changes
    - gpus set and device is not set or instance device is None -> ValidationError
    - gpus is an empty list -> clear parent_gpubaseboard on any existing child GPUs
    - gpus is set, device is set or instance.device is not None and any gpu.device is not
        the same as the device value or the instance.device -> ValidationError
    - gpus is set, device is set or instance.device is not None -> set parent_gpubaseboard to
        instance for GPUs in the list, clear parent_gpubaseboard for any that are currently set
        to the instance but are not in the list
    - gpus not set or null and storage location set -> clear any existing child GPUs
    """
    # For update operations we need to know if the gpus field is present in the PUT/PATCH data,
    # as an empty list triggers clearing parent_gpubaseboard for current child GPUs
    gpus = validated_data.pop("gpus", None)

    location = validated_data.get("location", None)
    parent_device = None if location else validated_data.get("device", instance.device)

    try:
        with transaction.atomic():
            # An empty list means we're clearing the child GPUs for this GPUBasebaord
            # Moving a GPUBaseboard to a location means we need to clear any child GPUs
            if (gpus is not None and len(gpus) == 0) or location is not None:
                for gpu in instance.gpus.all():
                    gpu.parent_gpubaseboard = None
                    gpu.validated_save()

            elif gpus:
                # Validate the parent device
                validate_parent_device(gpus, parent_device)

                # Validate available slots
                baseboard_type = instance.fsu_type
                if (
                    baseboard_type.slot_count is not None
                    and len(gpus) > baseboard_type.slot_count
                ):
                    raise ValidationError(
                        f"Number of GPUs being added to Baseboard ({len(gpus)}) is greater "
                        f"than the number of available slots ({baseboard_type.slot_count})"
                    )

                # Track the currently set child GPUs to update properly
                # if the list has changed
                current_gpus = set(list(instance.gpus.all()))
                new_gpus = set()
                for gpu in gpus:
                    # New child GPUs must not have a parent GPUBaseboard assigned
                    if gpu not in current_gpus and gpu.parent_gpubaseboard is not None:
                        raise ValidationError(
                            f"GPU {gpu.name} is already assigned to "
                            f"{gpu.parent_gpubaseboard.name}"
                        )
                    new_gpus.add(gpu)

                # Set parent_gpubaseboard for newly added child GPUs
                for new_gpu in new_gpus.difference(current_gpus):
                    new_gpu.parent_gpubaseboard = instance
                    new_gpu.validated_save()

                # Remove any currently assigned child GPUs that are not in the updated list
                for gpu in current_gpus.difference(new_gpus):
                    gpu.parent_gpubaseboard = None
                    gpu.validated_save()

            validated_instance: GPUBaseboard = super().update(instance, validated_data)

    except ValidationError as error:
        raise serializers.ValidationError({"gpus": error.messages[0]}) from error

    return validated_instance
validate(data)

Need to hide the gpus field from normal validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def validate(self, data: Any):
    """Need to hide the gpus field from normal validation."""
    to_validate = copy(data)

    # Need to remove the list of gpus before the first validation step, otherwise the
    # model validation will complain because you can't set parent_gpubaseboard on the gpus in
    # this direction, that's handled in the create()/update() methods.
    _ = to_validate.pop("gpus", None)

    super().validate(to_validate)

    return data
GPUSerializer

Bases: FSUModelSerializer

API serializer for GPU model.

Source code in nautobot_fsus/api/serializers/fsus.py
class GPUSerializer(FSUModelSerializer):
    """API serializer for GPU model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:gpu-detail")

    class Meta(FSUModelSerializer.Meta):
        """GPUSerializer model options."""

        model = GPU
Meta

Bases: Meta

GPUSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """GPUSerializer model options."""

    model = GPU
HBASerializer

Bases: FSUModelSerializer

API serializer for HBA model.

Source code in nautobot_fsus/api/serializers/fsus.py
class HBASerializer(FSUModelSerializer):
    """API serializer for HBA model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:hba-detail")
    disks = serializers.PrimaryKeyRelatedField(
        queryset=Disk.objects.all(),
        many=True,
        required=False,
        allow_null=True,
    )

    class Meta(FSUModelSerializer.Meta):
        """HBASerializer model options."""

        model = HBA

    def validate(self, data: Any):
        """Need to hide the disks field from normal validation."""
        to_validate = copy(data)

        # Need to remove the list of disks before the first validation step, otherwise the
        # model validation will complain because you can't set parent_hba on the disks in
        # this direction, that's handled in the create()/update() methods.
        _ = to_validate.pop("disks", None)

        super().validate(to_validate)

        return data

    def create(self, validated_data: Any) -> HBA:
        """Create a new HBA instance with child Disk validation."""
        # disks is optional in the POST data, set it to an empty list if it's not present
        disks = validated_data.pop("disks", [])

        try:
            with transaction.atomic():
                if disks:
                    # Validate parent device
                    validate_parent_device(disks, validated_data.get("device", None))

                    # Child disks must not have a parent HBA assigned
                    for disk in disks:
                        if disk.parent_hba is not None:
                            raise ValidationError(
                                f"Disk {disk.name} is already assigned to {disk.parent_hba.name}"
                            )

                # Create the HBA instance
                instance: HBA = HBA.objects.create(**validated_data)

                # Set the parent_hba for any specified child Disk instances
                for disk in disks:
                    disk.parent_hba = instance
                    disk.validated_save()

        except ValidationError as error:
            raise serializers.ValidationError({"disks": error.messages[0]}) from error

        return instance

    def update(self, instance: HBA, validated_data: Any) -> HBA:
        """
        Update an existing HBA instance.

        PUT requests must have all required field, PATCH requests need only the changed fields.
        When updating an HBA instance, child Disks update logic is:
        - disks not set or null, device and storage location not updated -> no changes
        - disks set and device is not set or instance device is None -> ValidationError
        - disks is an empty list -> clear parent_hba on any existing child Disks
        - disks is set, device is set or instance.device is not None and any disk.device is not
            the same as the device value or the instance.device -> ValidationError
        - disks is set, device is set or instance.device is not None -> set parent_hba to
            instance for Disks in the list, clear parent_hba for any that are currently set
            to the instance but are not in the list
        - disks not set or null and storage location set -> clear any existing child Disks
        """
        # For update operations we need to know if the disks field is present in the PUT/PATCH data,
        # as an empty list triggers clearing parent_gpubaseboard for current child Disks
        disks = validated_data.pop("disks", None)

        location = validated_data.get("location", None)
        parent_device = None if location else validated_data.get("device", instance.device)

        try:
            with transaction.atomic():
                # An empty list means we're clearing the child Disks for this HBA
                # Moving an HBA to a location means we need to clear any child Disks
                if (disks is not None and len(disks) == 0) or location is not None:
                    for disk in instance.disks.all():
                        disk.parent_hba = None
                        disk.validated_save()

                elif disks:
                    # Validate the parent device
                    validate_parent_device(disks, parent_device)

                    # Track the currently set child Disks to update properly if the list has changed
                    current_disks = set(list(instance.disks.all()))
                    new_disks = set()
                    for disk in disks:
                        # New child Disks must not have a parent HBA assigned
                        if disk not in current_disks and disk.parent_hba is not None:
                            raise ValidationError(
                                f"Disk {disk.name} is already assigned to {disk.parent_hba.name}"
                            )
                        new_disks.add(disk)

                    # Set parent_hba for newly added child Disks
                    for new_disk in new_disks.difference(current_disks):
                        new_disk.parent_hba = instance
                        new_disk.validated_save()

                    # Remove any currently assigned child Disks that are not in the updated list
                    for disk in current_disks.difference(new_disks):
                        disk.parent_hba = None
                        disk.validated_save()

                validated_instance: HBA = super().update(instance, validated_data)

        except ValidationError as error:
            raise serializers.ValidationError({"disks": error.messages[0]}) from error

        return validated_instance
Meta

Bases: Meta

HBASerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """HBASerializer model options."""

    model = HBA
create(validated_data)

Create a new HBA instance with child Disk validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def create(self, validated_data: Any) -> HBA:
    """Create a new HBA instance with child Disk validation."""
    # disks is optional in the POST data, set it to an empty list if it's not present
    disks = validated_data.pop("disks", [])

    try:
        with transaction.atomic():
            if disks:
                # Validate parent device
                validate_parent_device(disks, validated_data.get("device", None))

                # Child disks must not have a parent HBA assigned
                for disk in disks:
                    if disk.parent_hba is not None:
                        raise ValidationError(
                            f"Disk {disk.name} is already assigned to {disk.parent_hba.name}"
                        )

            # Create the HBA instance
            instance: HBA = HBA.objects.create(**validated_data)

            # Set the parent_hba for any specified child Disk instances
            for disk in disks:
                disk.parent_hba = instance
                disk.validated_save()

    except ValidationError as error:
        raise serializers.ValidationError({"disks": error.messages[0]}) from error

    return instance
update(instance, validated_data)

Update an existing HBA instance.

PUT requests must have all required field, PATCH requests need only the changed fields. When updating an HBA instance, child Disks update logic is: - disks not set or null, device and storage location not updated -> no changes - disks set and device is not set or instance device is None -> ValidationError - disks is an empty list -> clear parent_hba on any existing child Disks - disks is set, device is set or instance.device is not None and any disk.device is not the same as the device value or the instance.device -> ValidationError - disks is set, device is set or instance.device is not None -> set parent_hba to instance for Disks in the list, clear parent_hba for any that are currently set to the instance but are not in the list - disks not set or null and storage location set -> clear any existing child Disks

Source code in nautobot_fsus/api/serializers/fsus.py
def update(self, instance: HBA, validated_data: Any) -> HBA:
    """
    Update an existing HBA instance.

    PUT requests must have all required field, PATCH requests need only the changed fields.
    When updating an HBA instance, child Disks update logic is:
    - disks not set or null, device and storage location not updated -> no changes
    - disks set and device is not set or instance device is None -> ValidationError
    - disks is an empty list -> clear parent_hba on any existing child Disks
    - disks is set, device is set or instance.device is not None and any disk.device is not
        the same as the device value or the instance.device -> ValidationError
    - disks is set, device is set or instance.device is not None -> set parent_hba to
        instance for Disks in the list, clear parent_hba for any that are currently set
        to the instance but are not in the list
    - disks not set or null and storage location set -> clear any existing child Disks
    """
    # For update operations we need to know if the disks field is present in the PUT/PATCH data,
    # as an empty list triggers clearing parent_gpubaseboard for current child Disks
    disks = validated_data.pop("disks", None)

    location = validated_data.get("location", None)
    parent_device = None if location else validated_data.get("device", instance.device)

    try:
        with transaction.atomic():
            # An empty list means we're clearing the child Disks for this HBA
            # Moving an HBA to a location means we need to clear any child Disks
            if (disks is not None and len(disks) == 0) or location is not None:
                for disk in instance.disks.all():
                    disk.parent_hba = None
                    disk.validated_save()

            elif disks:
                # Validate the parent device
                validate_parent_device(disks, parent_device)

                # Track the currently set child Disks to update properly if the list has changed
                current_disks = set(list(instance.disks.all()))
                new_disks = set()
                for disk in disks:
                    # New child Disks must not have a parent HBA assigned
                    if disk not in current_disks and disk.parent_hba is not None:
                        raise ValidationError(
                            f"Disk {disk.name} is already assigned to {disk.parent_hba.name}"
                        )
                    new_disks.add(disk)

                # Set parent_hba for newly added child Disks
                for new_disk in new_disks.difference(current_disks):
                    new_disk.parent_hba = instance
                    new_disk.validated_save()

                # Remove any currently assigned child Disks that are not in the updated list
                for disk in current_disks.difference(new_disks):
                    disk.parent_hba = None
                    disk.validated_save()

            validated_instance: HBA = super().update(instance, validated_data)

    except ValidationError as error:
        raise serializers.ValidationError({"disks": error.messages[0]}) from error

    return validated_instance
validate(data)

Need to hide the disks field from normal validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def validate(self, data: Any):
    """Need to hide the disks field from normal validation."""
    to_validate = copy(data)

    # Need to remove the list of disks before the first validation step, otherwise the
    # model validation will complain because you can't set parent_hba on the disks in
    # this direction, that's handled in the create()/update() methods.
    _ = to_validate.pop("disks", None)

    super().validate(to_validate)

    return data
MainboardSerializer

Bases: FSUModelSerializer

API serializer for Mainboard model.

Source code in nautobot_fsus/api/serializers/fsus.py
class MainboardSerializer(FSUModelSerializer):
    """API serializer for Mainboard model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:mainboard-detail")
    cpus = serializers.PrimaryKeyRelatedField(
        queryset=CPU.objects.all(),
        many=True,
        required=False,
        allow_null=True,
    )

    class Meta(FSUModelSerializer.Meta):
        """MainboardSerializer model options."""

        model = Mainboard

    def validate(self, data: Any):
        """Need to hide the cpus field from normal validation."""
        to_validate = copy(data)

        # Need to remove the list of cpus before the first validation step, otherwise the
        # model validation will complain because you can't set parent_mainboard on the cpus in
        # this direction, that's handled in the create()/update() methods.
        _ = to_validate.pop("cpus", None)

        super().validate(to_validate)

        return data

    def create(self, validated_data: Any) -> Mainboard:
        """Create a new Mainboard instance with child CPU validation."""
        # cpus is optional in the POST data, set it to an empty list if it's not present.
        cpus = validated_data.pop("cpus", [])

        try:
            with transaction.atomic():
                if cpus:
                    # Validate parent device
                    validate_parent_device(cpus, validated_data.get("device", None))

                    # Validate available sockets
                    mainboard_type = validated_data["fsu_type"]
                    if (
                        mainboard_type.cpu_socket_count is not None
                        and len(cpus) > mainboard_type.cpu_socket_count
                    ):
                        raise ValidationError(
                            f"Number of CPUs being added to Mainboard ({len(cpus)}) is "
                            f"greater than the number of available sockets "
                            f"({mainboard_type.cpu_socket_count})"
                        )

                    # Child CPUs must not have a parent Mainboard assigned
                    for cpu in cpus:
                        if cpu.parent_mainboard is not None:
                            raise ValidationError(
                                f"CPU {cpu.name} is already assigned "
                                f"to {cpu.parent_mainboard.name}"
                            )

                # Create the Mainboard instance
                instance: Mainboard = Mainboard.objects.create(**validated_data)

                # Set parent_mainboard for any specified child CPU instance
                for cpu in cpus:
                    cpu.parent_mainboard = instance
                    cpu.validated_save()

        except ValidationError as error:
            raise serializers.ValidationError({"cpus": error.messages[0]}) from error

        return instance

    def update(self, instance: Mainboard, validated_data: Any) -> Mainboard:
        """
        Update an existing Mainboard instance.

        PUT requests must have all required field, PATCH requests need only the changed fields.
        When updating a Mainboard instance, child CPUs update logic is:
        - cpus not set or null, device and storage location not updated -> no changes
        - cpus set and device is not set or instance device is None -> ValidationError
        - cpus is an empty list -> clear parent_mainboard on any existing child CPUs
        - cpus is set, device is set or instance.device is not None and any cpu.device is not
            the same as the device value or the instance.device -> ValidationError
        - cpus is set, device is set or instance.device is not None -> set parent_mainboard to
            instance for CPUs in the list, clear parent_mainboard for any that are currently set
            to the instance but are not in the list
        - cpus not set or null and storage location set -> clear any existing child CPUs
        """
        # For update operations we need to know if the cpus field is present in the PUT/PATCH data,
        # as an empty list triggers clearing parent_mainboard for current child CPUs
        cpus = validated_data.pop("cpus", None)

        location = validated_data.get("location", None)
        parent_device = None if location else validated_data.get("device", instance.device)

        try:
            with transaction.atomic():
                # An empty list means we're clearing the child CPUs for this Mainboard
                # Moving a Mainboard to a location means we need to clear any child CPUs
                if (cpus is not None and len(cpus) == 0) or location is not None:
                    for cpu in instance.cpus.all():
                        cpu.parent_mainboard = None
                        cpu.validated_save()

                elif cpus:
                    # Validate the parent device
                    validate_parent_device(cpus, parent_device)

                    # Validate available sockets
                    mainboard_type = instance.fsu_type
                    if (
                        mainboard_type.cpu_socket_count is not None
                        and len(cpus) > mainboard_type.cpu_socket_count
                    ):
                        raise ValidationError(
                            f"Number of CPUs being added to Mainboard ({len(cpus)}) is "
                            f"greater than the number of available sockets "
                            f"({mainboard_type.cpu_socket_count})"
                        )

                    # Track the currently set child CPUs to update properly if the list has changed
                    current_cpus = set(list(instance.cpus.all()))
                    new_cpus = set()
                    for cpu in cpus:
                        # New child CPU must not have a parent Mainboard assigned
                        if cpu not in current_cpus and cpu.parent_mainboard is not None:
                            raise ValidationError(
                                f"CPU {cpu.name} is already assigned "
                                f"to {cpu.parent_mainboard.name}"
                            )
                        new_cpus.add(cpu)

                    # Set parent_mainboard for newly added child CPUs
                    for new_cpu in new_cpus.difference(current_cpus):
                        new_cpu.parent_mainboard = instance
                        new_cpu.validated_save()

                    # Remove any currently assigned child CPUs that are not in the updated list
                    for cpu in current_cpus.difference(new_cpus):
                        cpu.parent_mainboard = None
                        cpu.validated_save()

                validated_instance: Mainboard = super().update(instance, validated_data)

        except ValidationError as error:
            raise serializers.ValidationError({"cpus": error.messages[0]}) from error

        return validated_instance
Meta

Bases: Meta

MainboardSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """MainboardSerializer model options."""

    model = Mainboard
create(validated_data)

Create a new Mainboard instance with child CPU validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def create(self, validated_data: Any) -> Mainboard:
    """Create a new Mainboard instance with child CPU validation."""
    # cpus is optional in the POST data, set it to an empty list if it's not present.
    cpus = validated_data.pop("cpus", [])

    try:
        with transaction.atomic():
            if cpus:
                # Validate parent device
                validate_parent_device(cpus, validated_data.get("device", None))

                # Validate available sockets
                mainboard_type = validated_data["fsu_type"]
                if (
                    mainboard_type.cpu_socket_count is not None
                    and len(cpus) > mainboard_type.cpu_socket_count
                ):
                    raise ValidationError(
                        f"Number of CPUs being added to Mainboard ({len(cpus)}) is "
                        f"greater than the number of available sockets "
                        f"({mainboard_type.cpu_socket_count})"
                    )

                # Child CPUs must not have a parent Mainboard assigned
                for cpu in cpus:
                    if cpu.parent_mainboard is not None:
                        raise ValidationError(
                            f"CPU {cpu.name} is already assigned "
                            f"to {cpu.parent_mainboard.name}"
                        )

            # Create the Mainboard instance
            instance: Mainboard = Mainboard.objects.create(**validated_data)

            # Set parent_mainboard for any specified child CPU instance
            for cpu in cpus:
                cpu.parent_mainboard = instance
                cpu.validated_save()

    except ValidationError as error:
        raise serializers.ValidationError({"cpus": error.messages[0]}) from error

    return instance
update(instance, validated_data)

Update an existing Mainboard instance.

PUT requests must have all required field, PATCH requests need only the changed fields. When updating a Mainboard instance, child CPUs update logic is: - cpus not set or null, device and storage location not updated -> no changes - cpus set and device is not set or instance device is None -> ValidationError - cpus is an empty list -> clear parent_mainboard on any existing child CPUs - cpus is set, device is set or instance.device is not None and any cpu.device is not the same as the device value or the instance.device -> ValidationError - cpus is set, device is set or instance.device is not None -> set parent_mainboard to instance for CPUs in the list, clear parent_mainboard for any that are currently set to the instance but are not in the list - cpus not set or null and storage location set -> clear any existing child CPUs

Source code in nautobot_fsus/api/serializers/fsus.py
def update(self, instance: Mainboard, validated_data: Any) -> Mainboard:
    """
    Update an existing Mainboard instance.

    PUT requests must have all required field, PATCH requests need only the changed fields.
    When updating a Mainboard instance, child CPUs update logic is:
    - cpus not set or null, device and storage location not updated -> no changes
    - cpus set and device is not set or instance device is None -> ValidationError
    - cpus is an empty list -> clear parent_mainboard on any existing child CPUs
    - cpus is set, device is set or instance.device is not None and any cpu.device is not
        the same as the device value or the instance.device -> ValidationError
    - cpus is set, device is set or instance.device is not None -> set parent_mainboard to
        instance for CPUs in the list, clear parent_mainboard for any that are currently set
        to the instance but are not in the list
    - cpus not set or null and storage location set -> clear any existing child CPUs
    """
    # For update operations we need to know if the cpus field is present in the PUT/PATCH data,
    # as an empty list triggers clearing parent_mainboard for current child CPUs
    cpus = validated_data.pop("cpus", None)

    location = validated_data.get("location", None)
    parent_device = None if location else validated_data.get("device", instance.device)

    try:
        with transaction.atomic():
            # An empty list means we're clearing the child CPUs for this Mainboard
            # Moving a Mainboard to a location means we need to clear any child CPUs
            if (cpus is not None and len(cpus) == 0) or location is not None:
                for cpu in instance.cpus.all():
                    cpu.parent_mainboard = None
                    cpu.validated_save()

            elif cpus:
                # Validate the parent device
                validate_parent_device(cpus, parent_device)

                # Validate available sockets
                mainboard_type = instance.fsu_type
                if (
                    mainboard_type.cpu_socket_count is not None
                    and len(cpus) > mainboard_type.cpu_socket_count
                ):
                    raise ValidationError(
                        f"Number of CPUs being added to Mainboard ({len(cpus)}) is "
                        f"greater than the number of available sockets "
                        f"({mainboard_type.cpu_socket_count})"
                    )

                # Track the currently set child CPUs to update properly if the list has changed
                current_cpus = set(list(instance.cpus.all()))
                new_cpus = set()
                for cpu in cpus:
                    # New child CPU must not have a parent Mainboard assigned
                    if cpu not in current_cpus and cpu.parent_mainboard is not None:
                        raise ValidationError(
                            f"CPU {cpu.name} is already assigned "
                            f"to {cpu.parent_mainboard.name}"
                        )
                    new_cpus.add(cpu)

                # Set parent_mainboard for newly added child CPUs
                for new_cpu in new_cpus.difference(current_cpus):
                    new_cpu.parent_mainboard = instance
                    new_cpu.validated_save()

                # Remove any currently assigned child CPUs that are not in the updated list
                for cpu in current_cpus.difference(new_cpus):
                    cpu.parent_mainboard = None
                    cpu.validated_save()

            validated_instance: Mainboard = super().update(instance, validated_data)

    except ValidationError as error:
        raise serializers.ValidationError({"cpus": error.messages[0]}) from error

    return validated_instance
validate(data)

Need to hide the cpus field from normal validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def validate(self, data: Any):
    """Need to hide the cpus field from normal validation."""
    to_validate = copy(data)

    # Need to remove the list of cpus before the first validation step, otherwise the
    # model validation will complain because you can't set parent_mainboard on the cpus in
    # this direction, that's handled in the create()/update() methods.
    _ = to_validate.pop("cpus", None)

    super().validate(to_validate)

    return data
NICSerializer

Bases: FSUModelSerializer

API serializer for NIC model.

Source code in nautobot_fsus/api/serializers/fsus.py
class NICSerializer(FSUModelSerializer):
    """API serializer for NIC model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:nic-detail")
    interfaces = serializers.PrimaryKeyRelatedField(
        queryset=Interface.objects.all(),
        many=True,
        required=False,
        allow_null=True,
    )

    class Meta(FSUModelSerializer.Meta):
        """NICSerializer model options."""

        model = NIC

    def create(self, validated_data: Any) -> NIC:
        """Create a new NIC instance with child Interface validation."""
        # interfaces field is optional in the POST data, set it to an empty list if it's not present
        interfaces = validated_data.pop("interfaces", [])

        try:
            with transaction.atomic():
                if interfaces:
                    # Validate the parent device
                    validate_parent_device(interfaces, validated_data.get("device", None))

                    # Validate available connections
                    nic_type = validated_data["fsu_type"]
                    if (
                        nic_type.interface_count is not None
                        and len(interfaces) > nic_type.interface_count
                    ):
                        raise ValidationError(
                            f"Number of Interfaces being added to NIC ({len(interfaces)}) is "
                            f"greater than the number of available connections "
                            f"({nic_type.interface_count})"
                        )

                    # Child Interfaces must not have a parent NIC assigned
                    for interface in interfaces:
                        if interface.parent_nic.first() is not None:
                            raise ValidationError(
                                f"interface {interface.name} is already assigned to "
                                f"{interface.parent_nic.first().name}"
                            )

                # Create the NIC instance
                instance: NIC = NIC.objects.create(**validated_data)

                # Add the child interfaces
                instance.interfaces.set(interfaces)

        except ValidationError as error:
            raise serializers.ValidationError({"interfaces": error.messages[0]}) from error

        return instance

    def update(self, instance: NIC, validated_data: Any) -> NIC:
        """
        Update an existing NIC instance.

        PUT requests must have all required field, PATCH requests need only the changed fields.
        When updating a NIC instance, child Interface update logic is:
        - interfaces not set or null, device and storage location not updated -> no changes
        - interfaces set and device is not set or instance device is None -> ValidationError
        - interfaces is an empty list -> clear parent_nic on any existing child Interfaces
        - interfaces is set, device is set or instance.device is not None and any interfaces.device
            is not the same as the device value or the instance.device -> ValidationError
        - interfaces is set, device is set or instance.device is not None -> set parent_nic to
            instance for Interfaces in the list, clear parent_nic for any that are currently set
            to the instance but are not in the list
        - interfaces not set or null and storage location set -> clear any existing child Interfaces
        """
        # For update operations we need to know if the interfaces field is present in the
        # PUT/PATCH data, as an empty list triggers clearing parent_nic for current child Interfaces
        interfaces = validated_data.pop("interfaces", None)

        location = validated_data.get("location", None)
        parent_device = None if location else validated_data.get("device", instance.device)

        try:
            with transaction.atomic():
                # An empty list means we're clearing the child Interfaces for this NIC
                # Moving a NIC to a location means we need to clear any child Interfaces
                if (interfaces is not None and len(interfaces) == 0) or location is not None:
                    instance.interfaces.clear()

                elif interfaces:
                    # Validate the parent device
                    validate_parent_device(interfaces, parent_device)

                    # Validate available slots
                    nic_type = instance.fsu_type
                    if (
                        nic_type.interface_count is not None
                        and len(interfaces) > nic_type.interface_count
                    ):
                        raise ValidationError(
                            f"Number of Interfaces being added to NIC ({len(interfaces)}) is "
                            f"greater than the number of available connections "
                            f"({nic_type.interface_count})"
                        )

                    # New child Interface must not have a parent NIC assigned
                    current_interfaces = set(list(instance.interfaces.all()))
                    for interface in interfaces:
                        if (
                            interface not in current_interfaces
                            and interface.parent_nic.first() is not None
                        ):
                            raise ValidationError(
                                f"interface {interface.name} is already assigned to "
                                f"{interface.parent_nic.first().name}"
                            )

                    # Set the new interface list on the NIC
                    instance.interfaces.set(interfaces)

                validated_instance: NIC = super().update(instance, validated_data)

        except ValidationError as error:
            raise serializers.ValidationError({"interfaces": error.messages[0]}) from error

        return validated_instance
Meta

Bases: Meta

NICSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """NICSerializer model options."""

    model = NIC
create(validated_data)

Create a new NIC instance with child Interface validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def create(self, validated_data: Any) -> NIC:
    """Create a new NIC instance with child Interface validation."""
    # interfaces field is optional in the POST data, set it to an empty list if it's not present
    interfaces = validated_data.pop("interfaces", [])

    try:
        with transaction.atomic():
            if interfaces:
                # Validate the parent device
                validate_parent_device(interfaces, validated_data.get("device", None))

                # Validate available connections
                nic_type = validated_data["fsu_type"]
                if (
                    nic_type.interface_count is not None
                    and len(interfaces) > nic_type.interface_count
                ):
                    raise ValidationError(
                        f"Number of Interfaces being added to NIC ({len(interfaces)}) is "
                        f"greater than the number of available connections "
                        f"({nic_type.interface_count})"
                    )

                # Child Interfaces must not have a parent NIC assigned
                for interface in interfaces:
                    if interface.parent_nic.first() is not None:
                        raise ValidationError(
                            f"interface {interface.name} is already assigned to "
                            f"{interface.parent_nic.first().name}"
                        )

            # Create the NIC instance
            instance: NIC = NIC.objects.create(**validated_data)

            # Add the child interfaces
            instance.interfaces.set(interfaces)

    except ValidationError as error:
        raise serializers.ValidationError({"interfaces": error.messages[0]}) from error

    return instance
update(instance, validated_data)

Update an existing NIC instance.

PUT requests must have all required field, PATCH requests need only the changed fields. When updating a NIC instance, child Interface update logic is: - interfaces not set or null, device and storage location not updated -> no changes - interfaces set and device is not set or instance device is None -> ValidationError - interfaces is an empty list -> clear parent_nic on any existing child Interfaces - interfaces is set, device is set or instance.device is not None and any interfaces.device is not the same as the device value or the instance.device -> ValidationError - interfaces is set, device is set or instance.device is not None -> set parent_nic to instance for Interfaces in the list, clear parent_nic for any that are currently set to the instance but are not in the list - interfaces not set or null and storage location set -> clear any existing child Interfaces

Source code in nautobot_fsus/api/serializers/fsus.py
def update(self, instance: NIC, validated_data: Any) -> NIC:
    """
    Update an existing NIC instance.

    PUT requests must have all required field, PATCH requests need only the changed fields.
    When updating a NIC instance, child Interface update logic is:
    - interfaces not set or null, device and storage location not updated -> no changes
    - interfaces set and device is not set or instance device is None -> ValidationError
    - interfaces is an empty list -> clear parent_nic on any existing child Interfaces
    - interfaces is set, device is set or instance.device is not None and any interfaces.device
        is not the same as the device value or the instance.device -> ValidationError
    - interfaces is set, device is set or instance.device is not None -> set parent_nic to
        instance for Interfaces in the list, clear parent_nic for any that are currently set
        to the instance but are not in the list
    - interfaces not set or null and storage location set -> clear any existing child Interfaces
    """
    # For update operations we need to know if the interfaces field is present in the
    # PUT/PATCH data, as an empty list triggers clearing parent_nic for current child Interfaces
    interfaces = validated_data.pop("interfaces", None)

    location = validated_data.get("location", None)
    parent_device = None if location else validated_data.get("device", instance.device)

    try:
        with transaction.atomic():
            # An empty list means we're clearing the child Interfaces for this NIC
            # Moving a NIC to a location means we need to clear any child Interfaces
            if (interfaces is not None and len(interfaces) == 0) or location is not None:
                instance.interfaces.clear()

            elif interfaces:
                # Validate the parent device
                validate_parent_device(interfaces, parent_device)

                # Validate available slots
                nic_type = instance.fsu_type
                if (
                    nic_type.interface_count is not None
                    and len(interfaces) > nic_type.interface_count
                ):
                    raise ValidationError(
                        f"Number of Interfaces being added to NIC ({len(interfaces)}) is "
                        f"greater than the number of available connections "
                        f"({nic_type.interface_count})"
                    )

                # New child Interface must not have a parent NIC assigned
                current_interfaces = set(list(instance.interfaces.all()))
                for interface in interfaces:
                    if (
                        interface not in current_interfaces
                        and interface.parent_nic.first() is not None
                    ):
                        raise ValidationError(
                            f"interface {interface.name} is already assigned to "
                            f"{interface.parent_nic.first().name}"
                        )

                # Set the new interface list on the NIC
                instance.interfaces.set(interfaces)

            validated_instance: NIC = super().update(instance, validated_data)

    except ValidationError as error:
        raise serializers.ValidationError({"interfaces": error.messages[0]}) from error

    return validated_instance
OtherFSUSerializer

Bases: FSUModelSerializer

API serializer for Other FSU model.

Source code in nautobot_fsus/api/serializers/fsus.py
class OtherFSUSerializer(FSUModelSerializer):
    """API serializer for Other FSU model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:otherfsu-detail")

    class Meta(FSUModelSerializer.Meta):
        """OtherFSUSerializer model options."""

        model = OtherFSU
Meta

Bases: Meta

OtherFSUSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """OtherFSUSerializer model options."""

    model = OtherFSU
PSUSerializer

Bases: FSUModelSerializer

API serializer for PSU model.

Source code in nautobot_fsus/api/serializers/fsus.py
class PSUSerializer(FSUModelSerializer):
    """API serializer for PSU model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:psu-detail")
    power_ports = serializers.PrimaryKeyRelatedField(
        queryset=PowerPort.objects.all(),
        many=True,
        required=False,
        allow_null=True,
    )

    class Meta(FSUModelSerializer.Meta):
        """PSUSerializer model options."""

        model = PSU

    def create(self, validated_data: Any) -> PSU:
        """Create a new PSU instance with child PowerPort validation."""
        # power_ports field is optional in the POST data, set it to an empty list if it's not present
        power_ports = validated_data.pop("power_ports", [])

        try:
            with transaction.atomic():
                if power_ports:
                    # Validate the parent device
                    validate_parent_device(power_ports, validated_data.get("device", None))

                    # Child PowerPorts must not have a parent PSU assigned
                    for power_port in power_ports:
                        if power_port.parent_psu.first() is not None:
                            raise ValidationError(
                                f"power port {power_port.name} is already assigned to "
                                f"{power_port.parent_psu.first().name}"
                            )

                # Create the PSU instance
                instance: PSU = PSU.objects.create(**validated_data)

                # Add the child interfaces
                instance.power_ports.set(power_ports)

        except ValidationError as error:
            raise serializers.ValidationError({"power_ports": error.messages[0]}) from error

        return instance

    def update(self, instance: PSU, validated_data: Any) -> PSU:
        """
        Update an existing PSU instance.

        PUT requests must have all required field, PATCH requests need only the changed fields.
        When updating a PSU instance, child PowerPort update logic is:
        - power_ports not set or null, device and storage location not updated -> no changes
        - power_ports set and device is not set or instance device is None -> ValidationError
        - power_ports is an empty list -> clear power_ports on the instance
        - power_ports is set, device is set or instance.device is not None and any
            power_ports.device is not the same as the device value or the
            instance.device -> ValidationError
        - power_ports is set, device is set or instance.device is not None -> set power_ports
            on the instance to the new list.
        - power_ports not set or null and storage location set -> clear any existing child PowerPorts
        """
        # For update operations we need to know if the power_ports field is present in the
        # PUT/PATCH data, as an empty list triggers clearing parent_psu for current child PowerPorts
        power_ports = validated_data.pop("power_ports", None)

        location = validated_data.get("location", None)
        parent_device = None if location else validated_data.get("device", instance.device)

        try:
            with transaction.atomic():
                # An empty list means we're clearing the child PowerPorts for this PSU
                # Moving a PSU to a location means we need to clear any child PowerPorts
                if (power_ports is not None and len(power_ports) == 0) or location is not None:
                    instance.power_ports.clear()

                elif power_ports:
                    # Validate the parent device
                    validate_parent_device(power_ports, parent_device)

                    # New child PowerPorts must not have a parent PSU assigned
                    current_power_ports = set(list(instance.power_ports.all()))
                    for power_port in power_ports:
                        if (
                            power_port not in current_power_ports
                            and power_port.parent_psu.first() is not None
                        ):
                            raise ValidationError(
                                f"Power Port {power_port.name} is already assigned to "
                                f"{power_port.parent_psu.first().name}"
                            )

                    # Set the new interface list on the NIC
                    instance.power_ports.set(power_ports)

                validated_instance: PSU = super().update(instance, validated_data)

        except ValidationError as error:
            raise serializers.ValidationError({"power_ports": error.messages[0]}) from error

        return validated_instance
Meta

Bases: Meta

PSUSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """PSUSerializer model options."""

    model = PSU
create(validated_data)

Create a new PSU instance with child PowerPort validation.

Source code in nautobot_fsus/api/serializers/fsus.py
def create(self, validated_data: Any) -> PSU:
    """Create a new PSU instance with child PowerPort validation."""
    # power_ports field is optional in the POST data, set it to an empty list if it's not present
    power_ports = validated_data.pop("power_ports", [])

    try:
        with transaction.atomic():
            if power_ports:
                # Validate the parent device
                validate_parent_device(power_ports, validated_data.get("device", None))

                # Child PowerPorts must not have a parent PSU assigned
                for power_port in power_ports:
                    if power_port.parent_psu.first() is not None:
                        raise ValidationError(
                            f"power port {power_port.name} is already assigned to "
                            f"{power_port.parent_psu.first().name}"
                        )

            # Create the PSU instance
            instance: PSU = PSU.objects.create(**validated_data)

            # Add the child interfaces
            instance.power_ports.set(power_ports)

    except ValidationError as error:
        raise serializers.ValidationError({"power_ports": error.messages[0]}) from error

    return instance
update(instance, validated_data)

Update an existing PSU instance.

PUT requests must have all required field, PATCH requests need only the changed fields. When updating a PSU instance, child PowerPort update logic is: - power_ports not set or null, device and storage location not updated -> no changes - power_ports set and device is not set or instance device is None -> ValidationError - power_ports is an empty list -> clear power_ports on the instance - power_ports is set, device is set or instance.device is not None and any power_ports.device is not the same as the device value or the instance.device -> ValidationError - power_ports is set, device is set or instance.device is not None -> set power_ports on the instance to the new list. - power_ports not set or null and storage location set -> clear any existing child PowerPorts

Source code in nautobot_fsus/api/serializers/fsus.py
def update(self, instance: PSU, validated_data: Any) -> PSU:
    """
    Update an existing PSU instance.

    PUT requests must have all required field, PATCH requests need only the changed fields.
    When updating a PSU instance, child PowerPort update logic is:
    - power_ports not set or null, device and storage location not updated -> no changes
    - power_ports set and device is not set or instance device is None -> ValidationError
    - power_ports is an empty list -> clear power_ports on the instance
    - power_ports is set, device is set or instance.device is not None and any
        power_ports.device is not the same as the device value or the
        instance.device -> ValidationError
    - power_ports is set, device is set or instance.device is not None -> set power_ports
        on the instance to the new list.
    - power_ports not set or null and storage location set -> clear any existing child PowerPorts
    """
    # For update operations we need to know if the power_ports field is present in the
    # PUT/PATCH data, as an empty list triggers clearing parent_psu for current child PowerPorts
    power_ports = validated_data.pop("power_ports", None)

    location = validated_data.get("location", None)
    parent_device = None if location else validated_data.get("device", instance.device)

    try:
        with transaction.atomic():
            # An empty list means we're clearing the child PowerPorts for this PSU
            # Moving a PSU to a location means we need to clear any child PowerPorts
            if (power_ports is not None and len(power_ports) == 0) or location is not None:
                instance.power_ports.clear()

            elif power_ports:
                # Validate the parent device
                validate_parent_device(power_ports, parent_device)

                # New child PowerPorts must not have a parent PSU assigned
                current_power_ports = set(list(instance.power_ports.all()))
                for power_port in power_ports:
                    if (
                        power_port not in current_power_ports
                        and power_port.parent_psu.first() is not None
                    ):
                        raise ValidationError(
                            f"Power Port {power_port.name} is already assigned to "
                            f"{power_port.parent_psu.first().name}"
                        )

                # Set the new interface list on the NIC
                instance.power_ports.set(power_ports)

            validated_instance: PSU = super().update(instance, validated_data)

    except ValidationError as error:
        raise serializers.ValidationError({"power_ports": error.messages[0]}) from error

    return validated_instance
RAMModuleSerializer

Bases: FSUModelSerializer

API serializer for RAM Module model.

Source code in nautobot_fsus/api/serializers/fsus.py
class RAMModuleSerializer(FSUModelSerializer):
    """API serializer for RAM Module model."""

    url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_fsus-api:rammodule-detail")

    class Meta(FSUModelSerializer.Meta):
        """RAMModuleSerializer model options."""

        model = RAMModule
Meta

Bases: Meta

RAMModuleSerializer model options.

Source code in nautobot_fsus/api/serializers/fsus.py
class Meta(FSUModelSerializer.Meta):
    """RAMModuleSerializer model options."""

    model = RAMModule

urls

URL routes for FSU API endpoint views.

views

API endpoint views for the Nautobot FSUs app.

CPUAPIView

Bases: NautobotModelViewSet

API view set for CPUs.

Source code in nautobot_fsus/api/views.py
class CPUAPIView(NautobotModelViewSet):
    """API view set for CPUs."""

    queryset = models.CPU.objects.all()
    serializer_class = serializers.CPUSerializer
    filterset_class = filters.CPUFilterSet

CPUTemplateAPIView

Bases: NautobotModelViewSet

API view set for CPUTemplates.

Source code in nautobot_fsus/api/views.py
class CPUTemplateAPIView(NautobotModelViewSet):
    """API view set for CPUTemplates."""

    queryset = models.CPUTemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.CPUTemplateSerializer
    filterset_class = filters.CPUTemplateFilterSet

CPUTypeAPIView

Bases: NautobotModelViewSet

API view set for CPUTypes.

Source code in nautobot_fsus/api/views.py
class CPUTypeAPIView(NautobotModelViewSet):
    """API view set for CPUTypes."""

    queryset = models.CPUType.objects.all()
    serializer_class = serializers.CPUTypeSerializer
    filterset_class = filters.CPUTypeFilterSet

DiskAPIView

Bases: NautobotModelViewSet

API view set for Disks.

Source code in nautobot_fsus/api/views.py
class DiskAPIView(NautobotModelViewSet):
    """API view set for Disks."""

    queryset = models.Disk.objects.all()
    serializer_class = serializers.DiskSerializer
    filterset_class = filters.DiskFilterSet

DiskTemplateAPIView

Bases: NautobotModelViewSet

API view set for DiskTemplates.

Source code in nautobot_fsus/api/views.py
class DiskTemplateAPIView(NautobotModelViewSet):
    """API view set for DiskTemplates."""

    queryset = models.DiskTemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.DiskTemplateSerializer
    filterset_class = filters.DiskTemplateFilterSet

DiskTypeAPIView

Bases: NautobotModelViewSet

API view set for DiskTypes.

Source code in nautobot_fsus/api/views.py
class DiskTypeAPIView(NautobotModelViewSet):
    """API view set for DiskTypes."""

    queryset = models.DiskType.objects.all()
    serializer_class = serializers.DiskTypeSerializer
    filterset_class = filters.DiskTypeFilterSet

FanAPIView

Bases: NautobotModelViewSet

API view set for Fans.

Source code in nautobot_fsus/api/views.py
class FanAPIView(NautobotModelViewSet):
    """API view set for Fans."""

    queryset = models.Fan.objects.all()
    serializer_class = serializers.FanSerializer
    filterset_class = filters.FanFilterSet

FanTemplateAPIView

Bases: NautobotModelViewSet

API view set for FanTemplates.

Source code in nautobot_fsus/api/views.py
class FanTemplateAPIView(NautobotModelViewSet):
    """API view set for FanTemplates."""

    queryset = models.FanTemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.FanTemplateSerializer
    filterset_class = filters.FanTemplateFilterSet

FanTypeAPIView

Bases: NautobotModelViewSet

API view set for FanTypes.

Source code in nautobot_fsus/api/views.py
class FanTypeAPIView(NautobotModelViewSet):
    """API view set for FanTypes."""

    queryset = models.FanType.objects.all()
    serializer_class = serializers.FanTypeSerializer
    filterset_class = filters.FanTypeFilterSet

GPUAPIView

Bases: NautobotModelViewSet

API view set for GPUs.

Source code in nautobot_fsus/api/views.py
class GPUAPIView(NautobotModelViewSet):
    """API view set for GPUs."""

    queryset = models.GPU.objects.all()
    serializer_class = serializers.GPUSerializer
    filterset_class = filters.GPUFilterSet

GPUBaseboardAPIView

Bases: NautobotModelViewSet

API view set for GPU Baseboards.

Source code in nautobot_fsus/api/views.py
class GPUBaseboardAPIView(NautobotModelViewSet):
    """API view set for GPU Baseboards."""

    queryset = models.GPUBaseboard.objects.all()
    serializer_class = serializers.GPUBaseboardSerializer
    filterset_class = filters.GPUBaseboardFilterSet

GPUBaseboardTemplateAPIView

Bases: NautobotModelViewSet

API view set for GPU Baseboard Templates.

Source code in nautobot_fsus/api/views.py
class GPUBaseboardTemplateAPIView(NautobotModelViewSet):
    """API view set for GPU Baseboard Templates."""

    queryset = models.GPUBaseboardTemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.GPUBaseboardTemplateSerializer
    filterset_class = filters.GPUBaseboardTemplateFilterSet

GPUBaseboardTypeAPIView

Bases: NautobotModelViewSet

API view set for GPU Baseboard Types.

Source code in nautobot_fsus/api/views.py
class GPUBaseboardTypeAPIView(NautobotModelViewSet):
    """API view set for GPU Baseboard Types."""

    queryset = models.GPUBaseboardType.objects.all()
    serializer_class = serializers.GPUBaseboardTypeSerializer
    filterset_class = filters.GPUBaseboardTypeFilterSet

GPUTemplateAPIView

Bases: NautobotModelViewSet

API view set for GPUTemplates.

Source code in nautobot_fsus/api/views.py
class GPUTemplateAPIView(NautobotModelViewSet):
    """API view set for GPUTemplates."""

    queryset = models.GPUTemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.GPUTemplateSerializer
    filterset_class = filters.GPUTemplateFilterSet

GPUTypeAPIView

Bases: NautobotModelViewSet

API view set for GPUTypes.

Source code in nautobot_fsus/api/views.py
class GPUTypeAPIView(NautobotModelViewSet):
    """API view set for GPUTypes."""

    queryset = models.GPUType.objects.all()
    serializer_class = serializers.GPUTypeSerializer
    filterset_class = filters.GPUTypeFilterSet

HBAAPIView

Bases: NautobotModelViewSet

API view set for HBAs.

Source code in nautobot_fsus/api/views.py
class HBAAPIView(NautobotModelViewSet):
    """API view set for HBAs."""

    queryset = models.HBA.objects.all()
    serializer_class = serializers.HBASerializer
    filterset_class = filters.HBAFilterSet

HBATemplateAPIView

Bases: NautobotModelViewSet

API view set for HBA Templates.

Source code in nautobot_fsus/api/views.py
class HBATemplateAPIView(NautobotModelViewSet):
    """API view set for HBA Templates."""

    queryset = models.HBATemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.HBATemplateSerializer
    filterset_class = filters.HBATemplateFilterSet

HBATypeAPIView

Bases: NautobotModelViewSet

API view set for HBA Types.

Source code in nautobot_fsus/api/views.py
class HBATypeAPIView(NautobotModelViewSet):
    """API view set for HBA Types."""

    queryset = models.HBAType.objects.all()
    serializer_class = serializers.HBATypeSerializer
    filterset_class = filters.HBATypeFilterSet

MainboardAPIView

Bases: NautobotModelViewSet

API view set for Mainboards.

Source code in nautobot_fsus/api/views.py
class MainboardAPIView(NautobotModelViewSet):
    """API view set for Mainboards."""

    queryset = models.Mainboard.objects.all()
    serializer_class = serializers.MainboardSerializer
    filterset_class = filters.MainboardFilterSet

MainboardTemplateAPIView

Bases: NautobotModelViewSet

API view set for Mainboard Templates.

Source code in nautobot_fsus/api/views.py
class MainboardTemplateAPIView(NautobotModelViewSet):
    """API view set for Mainboard Templates."""

    queryset = models.MainboardTemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.MainboardTemplateSerializer
    filterset_class = filters.MainboardTemplateFilterSet

MainboardTypeAPIView

Bases: NautobotModelViewSet

API view set for Mainboard Types.

Source code in nautobot_fsus/api/views.py
class MainboardTypeAPIView(NautobotModelViewSet):
    """API view set for Mainboard Types."""

    queryset = models.MainboardType.objects.all()
    serializer_class = serializers.MainboardTypeSerializer
    filterset_class = filters.MainboardTypeFilterSet

NICAPIView

Bases: NautobotModelViewSet

API view set for NICs.

Source code in nautobot_fsus/api/views.py
class NICAPIView(NautobotModelViewSet):
    """API view set for NICs."""

    queryset = models.NIC.objects.all()
    serializer_class = serializers.NICSerializer
    filterset_class = filters.NICFilterSet

NICTemplateAPIView

Bases: NautobotModelViewSet

API view set for NIC Templates.

Source code in nautobot_fsus/api/views.py
class NICTemplateAPIView(NautobotModelViewSet):
    """API view set for NIC Templates."""

    queryset = models.NICTemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.NICTemplateSerializer
    filterset_class = filters.NICTemplateFilterSet

NICTypeAPIView

Bases: NautobotModelViewSet

API view set for NIC Types.

Source code in nautobot_fsus/api/views.py
class NICTypeAPIView(NautobotModelViewSet):
    """API view set for NIC Types."""

    queryset = models.NICType.objects.all()
    serializer_class = serializers.NICTypeSerializer
    filterset_class = filters.NICTypeFilterSet

OtherFSUAPIView

Bases: NautobotModelViewSet

API view set for Other FSUs.

Source code in nautobot_fsus/api/views.py
class OtherFSUAPIView(NautobotModelViewSet):
    """API view set for Other FSUs."""

    queryset = models.OtherFSU.objects.all()
    serializer_class = serializers.OtherFSUSerializer
    filterset_class = filters.OtherFSUFilterSet

OtherFSUTemplateAPIView

Bases: NautobotModelViewSet

API view set for Other FSU Templates.

Source code in nautobot_fsus/api/views.py
class OtherFSUTemplateAPIView(NautobotModelViewSet):
    """API view set for Other FSU Templates."""

    queryset = models.OtherFSUTemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.OtherFSUTemplateSerializer
    filterset_class = filters.OtherFSUTemplateFilterSet

OtherFSUTypeAPIView

Bases: NautobotModelViewSet

API view set for Other FSU Types.

Source code in nautobot_fsus/api/views.py
class OtherFSUTypeAPIView(NautobotModelViewSet):
    """API view set for Other FSU Types."""

    queryset = models.OtherFSUType.objects.all()
    serializer_class = serializers.OtherFSUTypeSerializer
    filterset_class = filters.OtherFSUTypeFilterSet

PSUAPIView

Bases: NautobotModelViewSet

API view set for PSUs.

Source code in nautobot_fsus/api/views.py
class PSUAPIView(NautobotModelViewSet):
    """API view set for PSUs."""

    queryset = models.PSU.objects.all()
    serializer_class = serializers.PSUSerializer
    filterset_class = filters.PSUFilterSet

PSUTemplateAPIView

Bases: NautobotModelViewSet

API view set for PSU Templates.

Source code in nautobot_fsus/api/views.py
class PSUTemplateAPIView(NautobotModelViewSet):
    """API view set for PSU Templates."""

    queryset = models.PSUTemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.PSUTemplateSerializer
    filterset_class = filters.PSUTemplateFilterSet

PSUTypeAPIView

Bases: NautobotModelViewSet

API view set for PSU Types.

Source code in nautobot_fsus/api/views.py
class PSUTypeAPIView(NautobotModelViewSet):
    """API view set for PSU Types."""

    queryset = models.PSUType.objects.all()
    serializer_class = serializers.PSUTypeSerializer
    filterset_class = filters.PSUTypeFilterSet

RAMModuleAPIView

Bases: NautobotModelViewSet

API view set for RAM Modules.

Source code in nautobot_fsus/api/views.py
class RAMModuleAPIView(NautobotModelViewSet):
    """API view set for RAM Modules."""

    queryset = models.RAMModule.objects.all()
    serializer_class = serializers.RAMModuleSerializer
    filterset_class = filters.RAMModuleFilterSet

RAMModuleTemplateAPIView

Bases: NautobotModelViewSet

API view set for RAM Module Templates.

Source code in nautobot_fsus/api/views.py
class RAMModuleTemplateAPIView(NautobotModelViewSet):
    """API view set for RAM Module Templates."""

    queryset = models.RAMModuleTemplate.objects.select_related("device_type__manufacturer")
    serializer_class = serializers.RAMModuleTemplateSerializer
    filterset_class = filters.RAMModuleTemplateFilterSet

RAMModuleTypeAPIView

Bases: NautobotModelViewSet

API view set for RAM Module Types.

Source code in nautobot_fsus/api/views.py
class RAMModuleTypeAPIView(NautobotModelViewSet):
    """API view set for RAM Module Types."""

    queryset = models.RAMModuleType.objects.all()
    serializer_class = serializers.RAMModuleTypeSerializer
    filterset_class = filters.RAMModuleTypeFilterSet