コード例 #1
0
class ManifestSerializer(SingleArtifactContentSerializer):
    """
    Serializer for Manifests.
    """

    digest = serializers.CharField(help_text="sha256 of the Manifest file")
    schema_version = serializers.IntegerField(
        help_text="Docker schema version")
    media_type = serializers.CharField(
        help_text="Docker media type of the file")
    blobs = DetailRelatedField(
        many=True,
        help_text="Blobs that are referenced by this Manifest",
        view_name='docker-blobs-detail',
        queryset=models.ManifestBlob.objects.all())
    config_blob = DetailRelatedField(
        many=False,
        help_text="Blob that contains configuration for this Manifest",
        view_name='docker-blobs-detail',
        queryset=models.ManifestBlob.objects.all())

    class Meta:
        fields = SingleArtifactContentSerializer.Meta.fields + (
            'digest',
            'schema_version',
            'media_type',
            'blobs',
            'config_blob',
        )
        model = models.ImageManifest
コード例 #2
0
class ManifestSignatureSerializer(NoArtifactContentSerializer):
    """
    Serializer for image manifest signatures.
    """

    name = serializers.CharField(
        help_text=
        "Signature name in the format of `digest_algo:manifest_digest@random_32_chars`"
    )
    digest = serializers.CharField(
        help_text="sha256 digest of the signature blob")
    type = serializers.CharField(
        help_text="Container signature type, e.g. 'atomic'")
    key_id = serializers.CharField(help_text="Signing key ID")
    timestamp = serializers.IntegerField(help_text="Timestamp of a signature")
    creator = serializers.CharField(help_text="Signature creator")
    signed_manifest = DetailRelatedField(
        many=False,
        help_text="Manifest that is signed",
        view_name="container-manifests-detail",
        queryset=models.Manifest.objects.all(),
    )

    class Meta:
        fields = NoArtifactContentSerializer.Meta.fields + (
            "name",
            "digest",
            "type",
            "key_id",
            "timestamp",
            "creator",
            "signed_manifest",
        )
        model = models.ManifestSignature
コード例 #3
0
class ModulemdSerializer(SingleArtifactContentUploadSerializer,
                         ContentChecksumSerializer):
    """
    Modulemd serializer.
    """

    name = serializers.CharField(help_text=_("Modulemd name."), )
    stream = serializers.CharField(help_text=_("Stream name."), )
    version = serializers.CharField(help_text=_("Modulemd version."), )
    context = serializers.CharField(help_text=_("Modulemd context."), )
    arch = serializers.CharField(help_text=_("Modulemd architecture."), )
    artifacts = serializers.JSONField(help_text=_("Modulemd artifacts."),
                                      allow_null=True)
    dependencies = serializers.JSONField(help_text=_("Modulemd dependencies."),
                                         allow_null=True)
    # TODO: The performance of this is not great, there's a noticable difference in response
    # time before/after. Since this will only return Package content hrefs, we might benefit
    # from creating a specialized version of this Field that can skip some of the work.
    packages = DetailRelatedField(help_text=_("Modulemd artifacts' packages."),
                                  allow_null=True,
                                  required=False,
                                  queryset=Package.objects.all(),
                                  many=True)

    class Meta:
        fields = SingleArtifactContentUploadSerializer.Meta.fields + (
            'name', 'stream', 'version', 'context', 'arch', 'artifacts',
            'dependencies', 'packages', 'sha256')
        model = Modulemd
コード例 #4
0
class InstallerFileIndexSerializer(MultipleArtifactContentSerializer):
    """
    A serializer for InstallerFileIndex.
    """

    component = CharField(
        help_text="Component of the component - architecture combination.",
        required=True)

    architecture = CharField(
        help_text="Architecture of the component - architecture combination.",
        required=True)

    relative_path = CharField(
        help_text=
        "Path of directory containing MD5SUMS and SHA256SUMS relative to url.",
        required=False,
    )

    release = DetailRelatedField(
        help_text="Release this index file belongs to.",
        many=False,
        queryset=ReleaseFile.objects.all(),
        view_name="deb-release-file-detail",
    )

    class Meta:
        fields = MultipleArtifactContentSerializer.Meta.fields + (
            "release",
            "component",
            "architecture",
            "relative_path",
        )
        model = InstallerFileIndex
コード例 #5
0
ファイル: comps.py プロジェクト: pulp/pulp_rpm
class CompsXmlSerializer(serializers.Serializer):
    """
    A serializer for comps.xml Upload API.
    """

    file = serializers.FileField(
        help_text=
        _("Full path of a comps.xml file that may be parsed into comps.xml Content units."
          ),
        required=True,
    )
    repository = DetailRelatedField(
        help_text=
        _("URI of an RPM repository the comps.xml content units should be associated to."
          ),
        required=False,
        write_only=True,
        view_name_pattern=r"repositories(-.*/.*)-detail",
        queryset=Repository.objects.all(),
    )

    replace = serializers.BooleanField(
        help_text=_(
            "If true, incoming comps.xml replaces existing comps-related ContentUnits in the "
            "specified repository."),
        required=False,
        write_only=True,
    )

    class Meta:
        fields = ("file", "repository", "replace")
コード例 #6
0
class FileDistributionSerializer(DistributionSerializer):
    """
    Serializer for File Distributions.
    """

    publication = DetailRelatedField(
        required=False,
        help_text=_("Publication to be served"),
        view_name_pattern=r"publications(-.*/.*)?-detail",
        queryset=models.Publication.objects.exclude(complete=False),
        allow_null=True,
    )

    def validate(self, data):
        """
        Ensure publication and repository are not set at the same time.

        This is needed here till https://pulp.plan.io/issues/8761 is resolved.
        """
        data = super().validate(data)
        repository_provided = data.get("repository", None)
        publication_provided = data.get("publication", None)

        if repository_provided and publication_provided:
            raise serializers.ValidationError(
                _("Only one of the attributes 'repository' and 'publication' "
                  "may be used simultaneously."))
        if repository_provided or publication_provided:
            data["repository"] = repository_provided
            data["publication"] = publication_provided
        return data

    class Meta:
        fields = DistributionSerializer.Meta.fields + ("publication", )
        model = FileDistribution
コード例 #7
0
class FilePublicationSerializer(PublicationSerializer):
    """
    Serializer for File Publications.
    """

    distributions = DetailRelatedField(
        help_text=
        _("This publication is currently hosted as defined by these distributions."
          ),
        source="distribution_set",
        view_name="filedistributions-detail",
        many=True,
        read_only=True,
    )
    manifest = serializers.CharField(
        help_text=
        _("Filename to use for manifest file containing metadata for all the files."
          ),
        default="PULP_MANIFEST",
        required=False,
    )

    class Meta:
        model = FilePublication
        fields = PublicationSerializer.Meta.fields + ("distributions",
                                                      "manifest")
コード例 #8
0
class CollectionVersionSignatureSerializer(NoArtifactContentSerializer):
    """
    A serializer for signature models.
    """

    signed_collection = DetailRelatedField(
        help_text=_("The content this signature is pointing to."),
        view_name_pattern=r"content(-.*/.*)-detail",
        queryset=CollectionVersion.objects.all(),
    )
    pubkey_fingerprint = serializers.CharField(help_text=_("The fingerprint of the public key."))
    signing_service = RelatedField(
        help_text=_("The signing service used to create the signature."),
        view_name="signing-services-detail",
        queryset=SigningService.objects.all(),
        allow_null=True,
    )

    class Meta:
        model = CollectionVersionSignature
        fields = NoArtifactContentSerializer.Meta.fields + (
            "signed_collection",
            "pubkey_fingerprint",
            "signing_service",
        )
コード例 #9
0
class Pulp2ContentSerializer(ModelSerializer):
    """
    A serializer for the Pulp2Content model
    """

    pulp_href = IdentityField(view_name="pulp2content-detail")
    pulp2_id = serializers.CharField(max_length=255)
    pulp2_content_type_id = serializers.CharField(max_length=255)
    pulp2_last_updated = serializers.IntegerField()
    pulp2_storage_path = serializers.CharField(allow_null=True)
    downloaded = serializers.BooleanField(default=False)
    pulp3_content = DetailRelatedField(
        required=False,
        allow_null=True,
        queryset=Pulp2Content.objects.all(),
        view_name_pattern=r"content(-.*/.*)?-detail",
    )

    pulp3_repository_version = serializers.SerializerMethodField(
        read_only=True)

    @extend_schema_field(field=serializers.CharField)
    def get_pulp3_repository_version(self, obj):
        """
        Get pulp3_repository_version href from pulp2repo if available
        """
        pulp2_repo = obj.pulp2_repo
        if pulp2_repo and pulp2_repo.is_migrated:
            pulp3_repo_href = get_pulp_href(pulp2_repo.pulp3_repository)
            pulp3_repo_version = pulp2_repo.pulp3_repository_version
            return f"{pulp3_repo_href}versions/{pulp3_repo_version.number}/"

    def to_representation(self, instance):
        """
        Do not serialize pulp3_repository_version if it is null.
        pulp3_repository_version is set only for content which can migrate from one pulp2_content
        unit into multiple pulp3_content units.
        Serializing pulp3_repository_version when it is not set can mislead users that migrated
        content doesn't belong to any pulp3_repository_version.
        """
        result = super(Pulp2ContentSerializer,
                       self).to_representation(instance)
        if not result.get("pulp3_repository_version"):
            result.pop("pulp3_repository_version", None)
        return result

    class Meta:
        fields = ModelSerializer.Meta.fields + (
            "pulp2_id",
            "pulp2_content_type_id",
            "pulp2_last_updated",
            "pulp2_storage_path",
            "downloaded",
            "pulp3_content",
            "pulp3_repository_version",
        )
        model = Pulp2Content
コード例 #10
0
ファイル: serializers.py プロジェクト: melcorr/pulp_container
class ContainerDistributionSerializer(RepositoryVersionDistributionSerializer):
    """
    A serializer for ContainerDistribution.
    """

    registry_path = RegistryPathField(
        source="base_path",
        read_only=True,
        help_text=_(
            "The Registry hostame/name/ to use with docker pull command defined by "
            "this distribution."),
    )
    content_guard = DetailRelatedField(
        required=False,
        help_text=
        _("An optional content-guard. If none is specified, a default one will be used."
          ),
        view_name=r"contentguards-container/content-redirect-detail",
        queryset=models.ContentRedirectContentGuard.objects.all(),
        allow_null=False,
    )

    def validate(self, data):
        """
        Validate the ContainterDistribution.

        Make sure there is an instance of ContentRedirectContentGuard always present in validated
        data.
        Validate that the distribution  is not serving a repository versions of a push repository.
        """
        validated_data = super().validate(data)
        if "content_guard" not in validated_data:
            try:
                validated_data[
                    "content_guard"] = models.ContentRedirectContentGuard.objects.get(
                        name="content redirect")
            except ObjectDoesNotExist:
                cg_serializer = ContentRedirectContentGuardSerializer(
                    data={"name": "content redirect"})
                cg_serializer.is_valid(raise_exception=True)
                validated_data["content_guard"] = cg_serializer.create(
                    cg_serializer.validated_data)
        if "repository_version" in validated_data:
            repository = validated_data["repository_version"].repository.cast()
            if repository.PUSH_ENABLED:
                raise serializers.ValidationError(
                    _("A container push repository cannot be distributed by specifying a "
                      "repository version."))
        return validated_data

    class Meta:
        model = models.ContainerDistribution
        fields = tuple(
            set(RepositoryVersionDistributionSerializer.Meta.fields) -
            {"base_url"}) + ("registry_path", )
コード例 #11
0
class PackageReleaseComponentSerializer(NoArtifactContentSerializer):
    """
    A Serializer for PackageReleaseComponent.
    """

    package = DetailRelatedField(
        help_text="Package that is contained in release_comonent.",
        many=False,
        queryset=ReleaseComponent.objects.all(),
        view_name="deb-release_component-detail",
    )
    release_component = DetailRelatedField(
        help_text="ReleaseComponent this package is contained in.",
        many=False,
        queryset=ReleaseComponent.objects.all(),
        view_name="deb-release_component-detail",
    )

    class Meta(NoArtifactContentSerializer.Meta):
        model = PackageReleaseComponent
        fields = NoArtifactContentSerializer.Meta.fields + ("package", "release_component")
コード例 #12
0
ファイル: serializers.py プロジェクト: melcorr/pulp_container
class ManifestSerializer(SingleArtifactContentSerializer):
    """
    Serializer for Manifests.
    """

    digest = serializers.CharField(help_text="sha256 of the Manifest file")
    schema_version = serializers.IntegerField(
        help_text="Manifest schema version")
    media_type = serializers.CharField(
        help_text="Manifest media type of the file")
    listed_manifests = DetailRelatedField(
        many=True,
        help_text="Manifests that are referenced by this Manifest List",
        view_name="container-manifests-detail",
        queryset=models.Manifest.objects.all(),
    )
    blobs = DetailRelatedField(
        many=True,
        help_text="Blobs that are referenced by this Manifest",
        view_name="container-blobs-detail",
        queryset=models.Blob.objects.all(),
    )
    config_blob = DetailRelatedField(
        many=False,
        required=False,
        help_text="Blob that contains configuration for this Manifest",
        view_name="container-blobs-detail",
        queryset=models.Blob.objects.all(),
    )

    class Meta:
        fields = SingleArtifactContentSerializer.Meta.fields + (
            "digest",
            "schema_version",
            "media_type",
            "listed_manifests",
            "config_blob",
            "blobs",
        )
        model = models.Manifest
コード例 #13
0
class FilePublicationSerializer(PublicationSerializer):
    """
    Serializer for File Publications.
    """

    publisher = DetailRelatedField(
        help_text=_('The publisher that created this publication.'),
        queryset=FilePublisher.objects.all(),
        required=False,
    )

    class Meta:
        fields = PublicationSerializer.Meta.fields + ('publisher',)
        model = FilePublication
コード例 #14
0
class ReleaseArchitectureSerializer(NoArtifactContentSerializer):
    """
    A Serializer for ReleaseArchitecture.
    """

    architecture = CharField(help_text="Name of the architecture.")
    release = DetailRelatedField(
        help_text="Release this architecture is contained in.",
        many=False,
        queryset=Release.objects.all(),
        view_name="deb-release-detail",
    )

    class Meta(NoArtifactContentSerializer.Meta):
        model = ReleaseArchitecture
        fields = NoArtifactContentSerializer.Meta.fields + ("architecture", "release")
コード例 #15
0
ファイル: repository.py プロジェクト: quba42/pulp_rpm
class RpmDistributionSerializer(DistributionSerializer):
    """
    Serializer for RPM Distributions.
    """

    publication = DetailRelatedField(
        required=False,
        help_text=_("Publication to be served"),
        view_name_pattern=r"publications(-.*/.*)?-detail",
        queryset=Publication.objects.exclude(complete=False),
        allow_null=True,
    )

    class Meta:
        fields = DistributionSerializer.Meta.fields + ("publication", )
        model = RpmDistribution
コード例 #16
0
class TagSerializer(NoArtifactContentSerializer):
    """
    Serializer for Tags.
    """

    name = serializers.CharField(help_text="Tag name")
    tagged_manifest = DetailRelatedField(
        many=False,
        help_text="Manifest that is tagged",
        view_name="container-manifests-detail",
        queryset=models.Manifest.objects.all(),
    )

    class Meta:
        fields = NoArtifactContentSerializer.Meta.fields + ("name", "tagged_manifest")
        model = models.Tag
コード例 #17
0
class ReleaseComponentSerializer(NoArtifactContentSerializer):
    """
    A Serializer for ReleaseComponent.
    """

    component = CharField(help_text="Name of the component.")
    release = DetailRelatedField(
        help_text="Release this component is contained in.",
        many=False,
        queryset=Release.objects.all(),
        view_name="deb-release-detail",
    )

    class Meta(NoArtifactContentSerializer.Meta):
        model = ReleaseComponent
        fields = NoArtifactContentSerializer.Meta.fields + ("component", "release")
コード例 #18
0
class ManifestTagSerializer(SingleArtifactContentSerializer):
    """
    Serializer for ManifestTags.
    """

    name = serializers.CharField(help_text="Tag name")
    manifest = DetailRelatedField(many=False,
                                  help_text="Manifest that is tagged",
                                  view_name='docker-manifests-detail',
                                  queryset=models.ImageManifest.objects.all())

    class Meta:
        fields = SingleArtifactContentSerializer.Meta.fields + (
            'name',
            'manifest',
        )
        model = models.ManifestTag
コード例 #19
0
ファイル: serializers.py プロジェクト: pulp/pulp_ansible
class CollectionVersionSignatureSerializer(NoArtifactContentUploadSerializer):
    """
    A serializer for signature models.
    """

    signed_collection = DetailRelatedField(
        help_text=_("The content this signature is pointing to."),
        view_name_pattern=r"content(-.*/.*)-detail",
        queryset=CollectionVersion.objects.all(),
    )
    pubkey_fingerprint = serializers.CharField(
        help_text=_("The fingerprint of the public key."),
        read_only=True,
    )
    signing_service = RelatedField(
        help_text=_("The signing service used to create the signature."),
        view_name="signing-services-detail",
        read_only=True,
        allow_null=True,
    )

    def __init__(self, *args, **kwargs):
        """Ensure `file` field is required."""
        super().__init__(*args, **kwargs)
        self.fields["file"].required = True

    def validate(self, data):
        """
        Verify the signature is valid before creating it.
        """
        data = super().validate(data)

        if "request" not in self.context:
            # Validate is called twice, first on the viewset, and second on the create task
            # data should be set up properly on the second time, when request isn't in context
            data = verify_signature_upload(data)

        return data

    class Meta:
        model = CollectionVersionSignature
        fields = NoArtifactContentUploadSerializer.Meta.fields + (
            "signed_collection",
            "pubkey_fingerprint",
            "signing_service",
        )
コード例 #20
0
class ModulemdSerializer(NoArtifactContentSerializer):
    """
    Modulemd serializer.
    """

    name = serializers.CharField(help_text=_("Modulemd name."), )
    stream = serializers.CharField(help_text=_("Stream name."), )
    version = serializers.CharField(help_text=_("Modulemd version."), )
    static_context = serializers.BooleanField(
        help_text=_("Modulemd static-context flag."),
        required=False,
    )
    context = serializers.CharField(help_text=_("Modulemd context."), )
    arch = serializers.CharField(help_text=_("Modulemd architecture."), )
    artifacts = serializers.JSONField(help_text=_("Modulemd artifacts."),
                                      allow_null=True)
    dependencies = serializers.JSONField(help_text=_("Modulemd dependencies."),
                                         allow_null=True)
    # TODO: The performance of this is not great, there's a noticable difference in response
    # time before/after. Since this will only return Package content hrefs, we might benefit
    # from creating a specialized version of this Field that can skip some of the work.
    packages = DetailRelatedField(
        help_text=_("Modulemd artifacts' packages."),
        allow_null=True,
        required=False,
        queryset=Package.objects.all(),
        view_name="content-rpm/packages-detail",
        many=True,
    )
    snippet = serializers.CharField(help_text=_("Modulemd snippet"),
                                    write_only=True)

    class Meta:
        fields = NoArtifactContentSerializer.Meta.fields + (
            "name",
            "stream",
            "version",
            "static_context",
            "context",
            "arch",
            "artifacts",
            "dependencies",
            "packages",
            "snippet",
        )
        model = Modulemd
コード例 #21
0
class Pulp2ContentSerializer(ModelSerializer):
    """
    A serializer for the Pulp2Content model
    """
    pulp_href = IdentityField(view_name='pulp2content-detail')
    pulp2_id = serializers.CharField(max_length=255)
    pulp2_content_type_id = serializers.CharField(max_length=255)
    pulp2_last_updated = serializers.IntegerField()
    pulp2_storage_path = serializers.CharField()
    downloaded = serializers.BooleanField(default=False)
    pulp3_content = DetailRelatedField(required=False,
                                       allow_null=True,
                                       queryset=Pulp2Content.objects.all())

    pulp3_repository_version = serializers.SerializerMethodField(
        read_only=True)

    @extend_schema_serializer(many=False)
    def get_pulp3_repository_version(self, obj):
        """
        Get pulp3_repository_version href from pulp2repo if available
        """
        pulp2_repo = obj.pulp2_repo
        if pulp2_repo and pulp2_repo.is_migrated:
            pulp3_repo_href = get_pulp_href(pulp2_repo.pulp3_repository)
            pulp3_repo_version = pulp2_repo.pulp3_repository_version
            return f"{pulp3_repo_href}versions/{pulp3_repo_version.number}/"

    def to_representation(self, instance):
        """
        Do not serialize pulp3_repository_version if it is null.
        """
        result = super(Pulp2ContentSerializer,
                       self).to_representation(instance)
        if not result.get('pulp3_repository_version'):
            del result['pulp3_repository_version']
        return result

    class Meta:
        fields = ModelSerializer.Meta.fields + (
            'pulp2_id', 'pulp2_content_type_id', 'pulp2_last_updated',
            'pulp2_storage_path', 'downloaded', 'pulp3_content',
            'pulp3_repository_version')
        model = Pulp2Content
コード例 #22
0
class Pulp2ContentSerializer(ModelSerializer):
    """
    A serializer for the Pulp2Content model
    """
    pulp_href = IdentityField(view_name='migration-plans-detail')
    pulp2_id = serializers.CharField(max_length=255)
    pulp2_content_type_id = serializers.CharField(max_length=255)
    pulp2_last_updated = serializers.IntegerField()
    pulp2_storage_path = serializers.CharField()
    downloaded = serializers.BooleanField(default=False)
    pulp3_content = DetailRelatedField(required=False,
                                       allow_null=True,
                                       queryset=Pulp2Content.objects.all())

    class Meta:
        fields = ModelSerializer.Meta.fields + (
            'pulp2_id', 'pulp2_content_type_id', 'pulp2_last_updated',
            'pulp2_storage_path', 'downloaded', 'pulp3_content')
        model = Pulp2Content
コード例 #23
0
ファイル: serializers.py プロジェクト: gmbnomis/pulp_docker
class TagSerializer(SingleArtifactContentSerializer):
    """
    Serializer for Tags.
    """

    name = serializers.CharField(help_text="Tag name")
    tagged_manifest = DetailRelatedField(
        many=False,
        help_text="Manifest that is tagged",
        view_name='docker-manifests-detail',
        queryset=models.Manifest.objects.all())

    class Meta:
        fields = SingleArtifactContentSerializer.Meta.fields + (
            'name',
            'tagged_manifest',
        )
        model = models.Tag
        ref_name = f'{model._meta.app_label}_{model._meta.model_name}'
コード例 #24
0
class CookbookDistributionSerializer(DistributionSerializer):
    """Serializer for the Distribution."""

    base_url = CookbookBaseURLField(
        source="base_path",
        read_only=True,
        help_text=_("The URL for accessing the universe API as defined by this distribution."),
    )

    publication = DetailRelatedField(
        required=False,
        help_text=_("Publication to be served"),
        view_name_pattern=r"publications(-.*/.*)?-detail",
        queryset=models.Publication.objects.exclude(complete=False),
        allow_null=True,
    )

    class Meta:
        fields = DistributionSerializer.Meta.fields + ("publication",)
        model = CookbookDistribution
コード例 #25
0
class UploadSerializerFieldsMixin(Serializer):
    """A mixin class that contains fields and methods common to content upload serializers."""

    file = FileField(
        help_text=
        _("An uploaded file that may be turned into the artifact of the content unit."
          ),
        required=False,
        write_only=True,
    )
    repository = DetailRelatedField(
        help_text=
        _("A URI of a repository the new content unit should be associated with."
          ),
        required=False,
        write_only=True,
        view_name_pattern=r"repositories(-.*/.*)-detail",
        queryset=Repository.objects.all(),
    )

    def create(self, validated_data):
        """
        Save a GenericContent unit.

        This must be used inside a task that locks on the Artifact and if given, the repository.
        """

        repository = validated_data.pop("repository", None)
        content = super().create(validated_data)

        if repository:
            repository.cast()
            content_to_add = self.Meta.model.objects.filter(pk=content.pk)

            # create new repo version with uploaded package
            with repository.new_version() as new_version:
                new_version.add_content(content_to_add)
        return content

    class Meta:
        fields = ("file", "repository")
コード例 #26
0
class DockerDistributionSerializer(ModelSerializer):
    """
    A serializer for DockerDistribution.
    """

    _href = IdentityField(view_name='docker-distributions-detail')
    name = serializers.CharField(
        help_text=_('A unique distribution name. Ex, `rawhide` and `stable`.'),
        validators=[
            validators.MaxLengthValidator(
                models.DockerDistribution._meta.get_field('name').max_length,
                message=_(
                    'Distribution name length must be less than {} characters'
                ).format(
                    models.DockerDistribution._meta.get_field(
                        'name').max_length)),
            UniqueValidator(queryset=models.DockerDistribution.objects.all())
        ])
    base_path = serializers.CharField(
        help_text=
        _('The base (relative) path component of the published url. Avoid paths that \
                    overlap with other distribution base paths (e.g. "foo" and "foo/bar")'
          ),
        validators=[
            validators.MaxLengthValidator(
                models.DockerDistribution._meta.get_field(
                    'base_path').max_length,
                message=
                _('Distribution base_path length must be less than {} characters'
                  ).format(
                      models.DockerDistribution._meta.get_field(
                          'base_path').max_length)),
            UniqueValidator(queryset=models.DockerDistribution.objects.all()),
        ])
    publisher = DetailRelatedField(
        required=False,
        help_text=_(
            'Publications created by this publisher and repository are automatically'
            'served as defined by this distribution'),
        queryset=models.DockerPublisher.objects.all(),
        allow_null=True)
    publication = RelatedField(
        required=False,
        help_text=_(
            'The publication being served as defined by this distribution'),
        queryset=Publication.objects.exclude(complete=False),
        view_name='publications-detail',
        allow_null=True)
    repository = RelatedField(
        required=False,
        help_text=_(
            'Publications created by this repository and publisher are automatically'
            'served as defined by this distribution'),
        queryset=Repository.objects.all(),
        view_name='repositories-detail',
        allow_null=True)
    registry_path = RegistryPathField(
        source='base_path',
        read_only=True,
        help_text=_(
            'The Registry hostame:port/name/ to use with docker pull command defined by '
            'this distribution.'))

    class Meta:
        model = models.DockerDistribution
        fields = ModelSerializer.Meta.fields + (
            'name',
            'base_path',
            'publisher',
            'publication',
            'registry_path',
            'repository',
            'content_guard',
        )

    def _validate_path_overlap(self, path):
        # look for any base paths nested in path
        search = path.split("/")[0]
        q = Q(base_path=search)
        for subdir in path.split("/")[1:]:
            search = "/".join((search, subdir))
            q |= Q(base_path=search)

        # look for any base paths that nest path
        q |= Q(base_path__startswith='{}/'.format(path))
        qs = models.DockerDistribution.objects.filter(q)

        if self.instance is not None:
            qs = qs.exclude(pk=self.instance.pk)

        match = qs.first()
        if match:
            raise serializers.ValidationError(
                detail=_("Overlaps with existing distribution '"
                         "{}'").format(match.name))

        return path

    def validate_base_path(self, path):
        """
        Validate that path is valid.

        Args:
            path (str): the path at which the registry will be served at
        """
        self._validate_relative_path(path)
        return self._validate_path_overlap(path)

    def validate(self, data):
        """
        Validates that the data dict has valid DockerDistribution info.

        Args:
            data (dict): dict representing a DockerDistribution
        """
        super().validate(data)

        if 'publisher' in data:
            publisher = data['publisher']
        elif self.instance:
            publisher = self.instance.publisher
        else:
            publisher = None

        if 'repository' in data:
            repository = data['repository']
        elif self.instance:
            repository = self.instance.repository
        else:
            repository = None

        if publisher and not repository:
            raise serializers.ValidationError({
                'repository':
                _("Repository must be set if "
                  "publisher is set.")
            })
        if repository and not publisher:
            raise serializers.ValidationError({
                'publisher':
                _("Publisher must be set if "
                  "repository is set.")
            })

        return data
コード例 #27
0
ファイル: content.py プロジェクト: wbclark/pulpcore
class SingleArtifactContentUploadSerializer(SingleArtifactContentSerializer):
    """
    A serializer for content_types with a single Artifact.

    The Artifact can either be specified via it's url, or a new file can be uploaded.
    Additionally a repository can be specified, to which the content unit will be added.

    When using this serializer, the creation of the real content must be wrapped in a task that
    locks the Artifact and when specified, the repository.
    """

    file = FileField(
        help_text=
        _("An uploaded file that should be turned into the artifact of the content unit."
          ),
        required=False,
        write_only=True,
    )
    repository = DetailRelatedField(
        help_text=
        _("A URI of a repository the new content unit should be associated with."
          ),
        required=False,
        write_only=True,
        queryset=Repository.objects.all(),
    )

    def __init__(self, *args, **kwargs):
        """Initializer for SingleArtifactContentUploadSerializer."""
        super().__init__(*args, **kwargs)
        if self.fields.get("artifact"):
            self.fields["artifact"].required = False

    def validate(self, data):
        """Validate that we have an Artifact or can create one."""

        data = super().validate(data)

        if "file" in data:
            if "artifact" in data:
                raise ValidationError(
                    _("Only one of 'file' and 'artifact' may be specified."))
            data["artifact"] = Artifact.init_and_validate(data.pop("file"))
        elif "artifact" not in data:
            raise ValidationError(
                _("One of 'file' and 'artifact' must be specified."))

        if "request" not in self.context:
            data = self.deferred_validate(data)

        return data

    def deferred_validate(self, data):
        """Validate the content unit by deeply analyzing the specified Artifact.

        This is only called when validating without a request context to prevent stalling
        an ongoing http request.
        It should be overwritten by plugins to extract metadata from the actual content in
        much the same way as `validate`.
        """
        return data

    def create(self, validated_data):
        """Save the GenericContent unit.
        This must be used inside a task that locks on the Artifact and if given, the repository.
        """

        repository = validated_data.pop("repository", None)
        content = super().create(validated_data)

        if repository:
            repository.cast()
            content_to_add = self.Meta.model.objects.filter(pk=content.pk)

            # create new repo version with uploaded package
            with repository.new_version() as new_version:
                new_version.add_content(content_to_add)
        return content

    class Meta(SingleArtifactContentSerializer.Meta):
        fields = SingleArtifactContentSerializer.Meta.fields + ("file",
                                                                "repository")
コード例 #28
0
class ContainerDistributionSerializer(DistributionSerializer):
    """
    A serializer for ContainerDistribution.
    """

    registry_path = RegistryPathField(
        source="base_path",
        read_only=True,
        help_text=_(
            "The Registry hostame/name/ to use with docker pull command defined by "
            "this distribution."
        ),
    )
    content_guard = DetailRelatedField(
        required=False,
        help_text=_("An optional content-guard. If none is specified, a default one will be used."),
        view_name=r"contentguards-container/content-redirect-detail",
        queryset=models.ContentRedirectContentGuard.objects.all(),
        allow_null=False,
    )
    namespace = RelatedField(
        required=False,
        read_only=True,
        view_name="pulp_container/namespaces-detail",
        help_text=_("Namespace this distribution belongs to."),
    )
    description = serializers.CharField(
        help_text=_("An optional description."), required=False, allow_null=True
    )
    repository_version = RepositoryVersionRelatedField(
        required=False, help_text=_("RepositoryVersion to be served"), allow_null=True
    )

    def validate(self, data):
        """
        Validate the ContainterDistribution.

        Make sure there is an instance of ContentRedirectContentGuard always present in validated
        data.
        Validate that the distribution  is not serving a repository versions of a push repository.
        """
        validated_data = super().validate(data)
        if "content_guard" not in validated_data:
            validated_data["content_guard"] = ContentRedirectContentGuardSerializer.get_or_create(
                {"name": "content redirect"}
            )
        if "repository_version" in validated_data:
            repository = validated_data["repository_version"].repository.cast()
            if repository.PUSH_ENABLED:
                raise serializers.ValidationError(
                    _(
                        "A container push repository cannot be distributed by specifying a "
                        "repository version."
                    )
                )

        if "base_path" in validated_data:
            base_path = validated_data["base_path"]
            namespace_name = base_path.split("/")[0]

            if "namespace" in validated_data:
                if validated_data["namespace"].name != namespace_name:
                    raise serializers.ValidationError(
                        _("Selected namespace does not match first component of base_path.")
                    )
            else:
                validated_data["namespace"] = ContainerNamespaceSerializer.get_or_create(
                    {"name": namespace_name}
                )
        return validated_data

    class Meta:
        model = models.ContainerDistribution
        fields = tuple(set(DistributionSerializer.Meta.fields) - {"base_url"}) + (
            "repository_version",
            "registry_path",
            "namespace",
            "private",
            "description",
        )