예제 #1
0
class RepositoryVersionDistributionSerializer(BaseDistributionSerializer):
    repository = DetailRelatedField(
        required=False,
        help_text=_(
            "The latest RepositoryVersion for this Repository will be served."
        ),
        view_name_pattern=r"repositories(-.*/.*)?-detail",
        queryset=models.Repository.objects.all(),
        allow_null=True,
    )
    repository_version = RepositoryVersionRelatedField(
        required=False,
        help_text=_("RepositoryVersion to be served"),
        allow_null=True)

    class Meta:
        abstract = True
        fields = BaseDistributionSerializer.Meta.fields + (
            "repository", "repository_version")

    def validate(self, data):
        super().validate(data)

        repository_in_data = "repository" in data
        repository_version_in_data = "repository_version" in data
        repository_in_instance = self.instance.repository if self.instance else None
        repository_version_in_instance = self.instance.repository_version if self.instance else None

        if repository_in_data and repository_version_in_data:
            error = True
        elif repository_in_data and repository_version_in_instance:
            error = True
        elif repository_in_instance and repository_version_in_data:
            error = True
        else:
            error = False

        if error:
            msg = _(
                "The attributes 'repository' and 'repository_version' must be used exclusively."
            )
            raise serializers.ValidationError(msg)

        return data
예제 #2
0
class PublicationSerializer(ModelSerializer):
    pulp_href = DetailIdentityField(
        view_name_pattern=r"publications(-.*/.*)-detail")
    repository_version = RepositoryVersionRelatedField(required=False)
    repository = DetailRelatedField(
        help_text=_("A URI of the repository to be published."),
        required=False,
        label=_("Repository"),
        view_name_pattern=r"repositories(-.*/.*)?-detail",
        queryset=models.Repository.objects.all(),
    )

    def validate(self, data):
        if hasattr(self, "initial_data"):
            validate_unknown_fields(self.initial_data, self.fields)

        repository = data.pop("repository",
                              None)  # not an actual field on publication
        repository_version = data.get("repository_version")
        if not repository and not repository_version:
            raise serializers.ValidationError(
                _("Either the 'repository' or 'repository_version' need to be specified"
                  ))
        elif not repository and repository_version:
            return data
        elif repository and not repository_version:
            version = repository.latest_version()
            if version:
                new_data = {"repository_version": version}
                new_data.update(data)
                return new_data
            else:
                raise serializers.ValidationError(detail=_(
                    "Repository has no version available to create Publication from"
                ))
        raise serializers.ValidationError(
            _("Either the 'repository' or 'repository_version' need to be specified "
              "but not both."))

    class Meta:
        abstract = True
        model = models.Publication
        fields = ModelSerializer.Meta.fields + ("repository_version",
                                                "repository")
예제 #3
0
class RepositoryVersionSerializer(ModelSerializer, NestedHyperlinkedModelSerializer):
    pulp_href = RepositoryVersionIdentityField()
    number = serializers.IntegerField(
        read_only=True
    )
    base_version = RepositoryVersionRelatedField(
        required=False,
        help_text=_('A repository version whose content was used as the initial set of content '
                    'for this repository version'),
    )
    content_summary = ContentSummarySerializer(
        help_text=_('Various count summaries of the content in the version and the HREF to view '
                    'them.'),
        source="*",
        read_only=True,
    )

    class Meta:
        model = models.RepositoryVersion
        fields = ModelSerializer.Meta.fields + (
            'pulp_href', 'number', 'base_version', 'content_summary',
        )
예제 #4
0
class Pulp2RepositoriesSerializer(ModelSerializer):
    """
    A serializer for the Pulp2Repositories
    """
    pulp_href = IdentityField(view_name='pulp2repositories-detail')
    pulp2_object_id = serializers.CharField(max_length=255)
    pulp2_repo_id = serializers.CharField()
    pulp2_repo_type = serializers.CharField()
    is_migrated = serializers.BooleanField(default=False)
    not_in_plan = serializers.BooleanField(default=False)

    pulp3_repository_version = RepositoryVersionRelatedField(
        required=False,
        help_text=_('RepositoryVersion to be served'),
        allow_null=True,
    )

    pulp3_remote_href = serializers.SerializerMethodField(read_only=True)
    pulp3_publication_href = serializers.SerializerMethodField(read_only=True)
    pulp3_distribution_hrefs = serializers.SerializerMethodField(
        read_only=True)
    pulp3_repository_href = serializers.SerializerMethodField(read_only=True)

    @extend_schema_serializer(many=False)
    def get_pulp3_repository_href(self, obj):
        """
        Get pulp3_repository_href from pulp2repo
        """
        rv = obj.pulp3_repository_version
        if rv:
            return get_pulp_href(rv.repository)

    @extend_schema_serializer(many=False)
    def get_pulp3_remote_href(self, obj):
        """
        Get pulp3_remote_href from pulp2repo
        """
        remote = obj.pulp3_repository_remote
        if remote:
            return get_pulp_href(remote)

    @extend_schema_serializer(many=False)
    def get_pulp3_publication_href(self, obj):
        """
        Get pulp3_publication_href from pulp3_repository_version
        """
        rv = obj.pulp3_repository_version
        if rv:
            return get_pulp_href(rv.publication_set.first())

    @extend_schema_serializer(many=True)
    def get_pulp3_distribution_hrefs(self, obj):
        """
        Get pulp3_distribution_hrefs from pulp3_repository_version
        """
        dist_list = []
        rv = obj.pulp3_repository_version
        if not rv:
            return dist_list
        result_qs = rv.publication_set.all()
        if result_qs:
            # repo_version  has publication, therefore is a PublicationDistribution
            for publication in result_qs:
                distribution_type = f'{publication.pulp_type.replace(".", "_")}distribution'
                plugin_distribution = getattr(publication, distribution_type)
                dist_list.extend(plugin_distribution.all())
        else:
            # empty result_qs means that repo_version does not need publication,
            # or repo_version was not published/distributed
            pulp_type = rv.repository.pulp_type
            distribution_type = f'{pulp_type.replace(".", "_")}distribution'
            if hasattr(rv, distribution_type):
                # repo_version is distributed directly trough RepositoryDistribution
                plugin_distribution = getattr(rv, distribution_type)
                dist_list = plugin_distribution.all()
            else:
                # repo_version was not published/distributed
                return dist_list
        return [get_pulp_href(dist) for dist in dist_list]

    class Meta:
        fields = ModelSerializer.Meta.fields + (
            "pulp2_object_id",
            "pulp2_repo_id",
            "pulp2_repo_type",
            "is_migrated",
            "not_in_plan",
            "pulp3_repository_version",
            "pulp3_remote_href",
            "pulp3_publication_href",
            "pulp3_distribution_hrefs",
            "pulp3_repository_href",
        )
        model = Pulp2Repository
예제 #5
0
class PulpExportSerializer(ExportSerializer):
    """
    Serializer for PulpExports.
    """

    output_file_info = serializers.JSONField(
        help_text=
        _("Dictionary of filename: sha256hash entries for export-output-file(s)"
          ),
        read_only=True,
    )

    toc_info = serializers.JSONField(
        help_text=_(
            "Filename and sha256-checksum of table-of-contents for this export"
        ),
        read_only=True,
    )

    dry_run = serializers.BooleanField(
        help_text=_(
            "Generate report on what would be exported and disk-space required."
        ),
        default=False,
        required=False,
        write_only=True,
    )
    full = serializers.BooleanField(
        help_text=_("Do a Full (true) or Incremental (false) export."),
        default=True,
        required=False,
        write_only=True,
    )
    versions = RepositoryVersionRelatedField(
        help_text=
        _("List of explicit repo-version hrefs to export (replaces current_version)."
          ),
        many=True,
        required=False,
        write_only=True,
    )

    MAX_CHUNK_BYTES = 1024 * 1024 * 1024 * 1024  # 1 TB
    chunk_size = serializers.CharField(
        help_text=_(
            "Chunk export-tarfile into pieces of chunk_size bytes. " +
            "Recognizes units of B/KB/MB/GB/TB. A chunk has a maximum " +
            "size of 1TB."),
        required=False,
        write_only=True,
    )

    start_versions = RepositoryVersionRelatedField(
        help_text=
        _("List of explicit last-exported-repo-version hrefs (replaces last_export)."
          ),
        many=True,
        required=False,
        write_only=True,
    )

    def _validate_versions_to_repos(self, the_versions):
        """
        If specifying repo-versions explicitly, must provide a version for each exporter-repository
        """
        # make sure counts match
        the_exporter = self.context.get("exporter", None)
        num_repos = the_exporter.repositories.count()
        if num_repos != len(the_versions):
            raise serializers.ValidationError(
                _("Number of versions ({}) does not match the number of Repositories ({}) for "
                  + "the owning  Exporter!").format(num_repos,
                                                    len(the_versions)))

        # make sure the specified versions 'belong to' the exporter.repositories
        exporter_repos = set(the_exporter.repositories.all())
        version_repos = set([vers.repository for vers in the_versions])
        if exporter_repos != version_repos:
            raise serializers.ValidationError(
                _("Requested RepositoryVersions must belong to the Repositories named by the "
                  + "Exporter!"))
        return the_versions

    def validate_versions(self, versions):
        return self._validate_versions_to_repos(versions)

    def validate_start_versions(self, start_versions):
        return self._validate_versions_to_repos(start_versions)

    def validate(self, data):
        # If we requested start_versions, make sure we did not forget to specify full=False
        if data.get("start_versions", None) and data.get("full", True):
            raise serializers.ValidationError(
                _("start_versions is only valid for incremental exports (full=False)"
                  ))

        # If we requested full=False, make sure we either specified start_versions= or
        # have a previous-export for our Exporter.
        if not data.get("full", True):
            the_exporter = self.context.get("exporter", None)
            if not data.get("start_versions",
                            None) and not the_exporter.last_export:
                raise serializers.ValidationError(
                    _("Incremental export can only be requested when there is a previous export "
                      + "or start_versions= has been specified."))
        return super().validate(data)

    @staticmethod
    def _parse_size(size):
        try:
            # based on https://stackoverflow.com/a/42865957/2002471
            units = {
                "B": 1,
                "KB": 2**10,
                "MB": 2**20,
                "GB": 2**30,
                "TB": 2**40
            }
            size = size.upper()
            if not re.match(r" ", size):
                size = re.sub(r"([KMGT]?B)", r" \1", size)
            number, unit = [string.strip() for string in size.split()]
            return int(float(number) * units[unit])
        except ValueError:
            raise serializers.ValidationError(
                _("chunk_size '{}' is not valid (valid units are B/KB/MB/GB/TB)"
                  ).format(size))

    def validate_chunk_size(self, chunk_size):
        the_size = self._parse_size(chunk_size)
        if the_size <= 0:
            raise serializers.ValidationError(
                _("Chunk size {} is not greater than zero!").format(the_size))
        if the_size > self.MAX_CHUNK_BYTES:
            raise serializers.ValidationError(
                _("Chunk size in bytes {} is greater than max-chunk-size {}!").
                format(the_size, self.MAX_CHUNK_BYTES))
        return the_size

    class Meta:
        model = models.PulpExport
        fields = ExportSerializer.Meta.fields + (
            "full",
            "dry_run",
            "versions",
            "chunk_size",
            "output_file_info",
            "start_versions",
            "toc_info",
        )
예제 #6
0
class Pulp2RepositoriesSerializer(ModelSerializer):
    """
    A serializer for the Pulp2Repositories
    """
    pulp_href = IdentityField(
        view_name='pulp2repositories-detail'
    )
    pulp2_object_id = serializers.CharField(max_length=255)
    pulp2_repo_id = serializers.CharField()
    pulp2_repo_type = serializers.CharField()
    is_migrated = serializers.BooleanField(default=False)
    not_in_plan = serializers.BooleanField(default=False)

    pulp3_repository_version = RepositoryVersionRelatedField(
        required=False,
        help_text=_('RepositoryVersion to be served'),
        allow_null=True,
    )

    pulp3_remote_href = serializers.SerializerMethodField(read_only=True)
    pulp3_publication_href = serializers.SerializerMethodField(read_only=True)
    pulp3_distribution_hrefs = serializers.SerializerMethodField(read_only=True)
    pulp3_repository_href = serializers.SerializerMethodField(read_only=True)

    @extend_schema_field(field=serializers.CharField)
    def get_pulp3_repository_href(self, obj):
        """
        Get pulp3_repository_href from pulp2repo
        """
        rv = obj.pulp3_repository_version
        if rv:
            return get_pulp_href(rv.repository)

    @extend_schema_field(field=serializers.CharField)
    def get_pulp3_remote_href(self, obj):
        """
        Get pulp3_remote_href from pulp2repo
        """
        remote = obj.pulp3_repository_remote
        if remote:
            return get_pulp_href(remote)

    @extend_schema_field(field=serializers.CharField)
    def get_pulp3_publication_href(self, obj):
        """
        Get pulp3_publication_href from pulp3_repository_version
        """
        rv = obj.pulp3_repository_version
        if rv:
            return get_pulp_href(rv.publication_set.filter(complete=True).first())

    @extend_schema_field(field=serializers.ListField(child=serializers.CharField()))
    def get_pulp3_distribution_hrefs(self, obj):
        """
        Get pulp3_distribution_hrefs from pulp3_repository_version
        """
        pulp2dists = obj.pulp2_dists.filter(not_in_plan=False, is_migrated=True)
        return [get_pulp_href(dist.pulp3_distribution) for dist in pulp2dists]

    class Meta:
        fields = ModelSerializer.Meta.fields + (
            "pulp2_object_id",
            "pulp2_repo_id",
            "pulp2_repo_type",
            "is_migrated",
            "not_in_plan",
            "pulp3_repository_version",
            "pulp3_remote_href",
            "pulp3_publication_href",
            "pulp3_distribution_hrefs",
            "pulp3_repository_href",
        )
        model = Pulp2Repository