Пример #1
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
Пример #2
0
class MigrationPlanSerializer(ModelSerializer):
    """Serializer for migration plan model."""
    _href = IdentityField(
        view_name='migration-plans-detail'
    )

    plan = serializers.JSONField(
        help_text=_('Migration Plan in JSON format'),
        required=True,
    )

    class Meta:
        fields = ModelSerializer.Meta.fields + ('plan', )
        model = MigrationPlan

    def validate(self, data):
        """
        Validate that the Serializer contains valid data.

        Validates JSON structure of migration_plan.
        Checks pulp2 and pulp3 plugins are installed.
        """
        schema = json.loads(SCHEMA)
        validator = Draft7Validator(schema)
        loaded_plan = json.loads(data['plan'])
        err = []
        for error in sorted(validator.iter_errors(loaded_plan), key=str):
            err.append(error.message)
        if err:
            raise serializers.ValidationError(
                _("Provided Migration Plan format is invalid:'{}'".format(err))
            )
        plugins_to_migrate = set()
        for plugin_type in loaded_plan['plugins']:
            plugins_to_migrate.add(plugin_type['type'])
        if len(loaded_plan['plugins']) != len(plugins_to_migrate):
            raise serializers.ValidationError(
                _("Provided Migration Plan contains same plugin type specified more that once.")
            )
        # MongoDB connection initialization
        connection.initialize()
        db = connection.get_database()
        for plugin in plugins_to_migrate:
            if PULP_2TO3_PLUGIN_MAP.get(plugin) not in INSTALLED_PULP_PLUGINS:
                raise serializers.ValidationError(
                    _("Plugin {} is not installed in pulp3.".format(plugin))
                )
            try:
                collection = PULP2_COLLECTION_MAP.get(plugin)
                db.command("collstats", collection)
            except OperationFailure:
                raise serializers.ValidationError(
                    _("Plugin {} is not installed in pulp2.".format(plugin))
                )
        data['plan'] = loaded_plan
        return data
Пример #3
0
class ContainerNamespaceSerializer(ModelSerializer, _GetOrCreateMixin):
    """
    Serializer for ContainerNamespaces.
    """

    pulp_href = IdentityField(view_name="pulp_container/namespaces-detail")

    class Meta:
        fields = ModelSerializer.Meta.fields + ("name",)
        model = models.ContainerNamespace
Пример #4
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
Пример #5
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
Пример #6
0
class AnsibleRoleSerializer(ContentSerializer):
    """
    A serializer for Ansible Roles.
    """

    name = serializers.CharField()
    namespace = serializers.CharField()

    _versions_href = IdentityField(
        view_name='versions-list',
        lookup_url_kwarg='role_pk',
    )

    version_count = serializers.IntegerField(source='versions.count',
                                             read_only=True)

    class Meta:
        fields = ('_href', 'name', 'namespace', '_versions_href',
                  'version_count')
        model = AnsibleRole
Пример #7
0
class MigrationPlanSerializer(ModelSerializer):
    _href = IdentityField(view_name='migration-plans-detail')

    plan = serializers.CharField(
        help_text=_('Migration Plan in JSON format'),
        required=True,
    )

    class Meta:
        fields = ModelSerializer.Meta.fields + ('plan', )
        model = MigrationPlan

    def validate(self, data):
        """
        Validate that the Serializer contains valid data.

        TODO:
        Validate JSON structure of migration_plan.
        Check validity of the JSON content:
         - migration for requested plugins is supported

        """
        return data
Пример #8
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
Пример #9
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
Пример #10
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()
    is_migrated = serializers.BooleanField(default=False)

    pulp3_repository_version = NestedRelatedField(
        view_name='versions-detail',
        lookup_field='number',
        parent_lookup_kwargs={'repository_pk': 'repository__pk'},
        queryset=RepositoryVersion.objects.all(),
        required=False,
    )

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

    def get_pulp3_remote_href(self, obj):
        """
        Get pulp3_remote_href from Pulp2Importer
        """
        importer = Pulp2Importer.objects.filter(pulp2_repository=obj).first()
        return get_pulp_href(importer.pulp3_remote)

    def get_pulp3_publisher_href(self, obj):
        """
        Get pulp3_publisher_href from Pulp2Distributor
        """
        distributors = getattr(self, "_distributors", None)
        if not distributors:
            self._distributors = Pulp2Distributor.objects.filter(
                pulp2_repository=obj).all()
            distributors = self._distributors

        return [
            get_pulp_href(d.pulp3_publisher) for d in distributors
            if d.pulp3_publisher
        ]

    def get_pulp3_publication_href(self, obj):
        """
        Get pulp3_publication_href from Pulp2Distributor
        """
        distributors = getattr(self, "_distributors", None)
        if not distributors:
            self._distributors = Pulp2Distributor.objects.filter(
                pulp2_repository=obj).all()
            distributors = self._distributors

        return [
            get_pulp_href(d.pulp3_publication) for d in distributors
            if d.pulp3_publication
        ]

    def get_pulp3_distribution_hrefs(self, obj):
        """
        Get pulp3_distribution_hrefs from Pulp2Distributor
        """
        distributors = getattr(self, "_distributors", None)
        if not distributors:
            self._distributors = Pulp2Distributor.objects.filter(
                pulp2_repository=obj).all()
            distributors = self._distributors

        return [
            get_pulp_href(d.pulp3_distribution) for d in distributors
            if d.pulp3_distribution
        ]

    class Meta:
        fields = ModelSerializer.Meta.fields + (
            "pulp2_object_id",
            "pulp2_repo_id",
            "is_migrated",
            "pulp3_repository_version",
            "pulp3_remote_href",
            "pulp3_publisher_href",
            "pulp3_publication_href",
            "pulp3_distribution_hrefs",
        )
        model = Pulp2Repository
Пример #11
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
Пример #12
0
class MigrationPlanSerializer(ModelSerializer):
    """Serializer for migration plan model."""

    pulp_href = IdentityField(view_name="migration-plans-detail")

    plan = serializers.JSONField(
        help_text=_("Migration Plan in JSON format"),
        required=True,
    )

    class Meta:
        fields = ModelSerializer.Meta.fields + ("plan", )
        model = MigrationPlan

    def validate(self, data):
        """
        Validate that the Serializer contains valid data.

        Validates JSON structure of migration_plan.
        Checks pulp2 and pulp3 plugins are installed.
        """
        schema = json.loads(SCHEMA)
        validator = Draft7Validator(schema)
        if isinstance(data["plan"], str):
            loaded_plan = json.loads(data["plan"])
        elif isinstance(data["plan"], dict):
            loaded_plan = data["plan"]
        else:
            raise serializers.ValidationError(
                _("Must provide a (JSON-encoded) string or dict for 'plan', not list"
                  ))
        err = []
        for error in sorted(validator.iter_errors(loaded_plan), key=str):
            err.append(error.message)
        if err:
            raise serializers.ValidationError(
                _("Provided Migration Plan format is invalid:'{}'".format(
                    err)))
        plugins_to_migrate = set()
        for plugin_type in loaded_plan["plugins"]:
            plugins_to_migrate.add(plugin_type["type"])
        if len(loaded_plan["plugins"]) != len(plugins_to_migrate):
            raise serializers.ValidationError(
                _("Provided Migration Plan contains same plugin type specified more that once."
                  ))
        # MongoDB connection initialization
        connection.initialize()
        db = connection.get_database()
        for plugin in plugins_to_migrate:
            plugin_migrator = PLUGIN_MIGRATORS.get(plugin)
            if not plugin_migrator:
                raise serializers.ValidationError(
                    _("Migration of {} plugin is not supported.".format(
                        plugin)))
            if plugin_migrator.pulp3_plugin not in INSTALLED_PULP_PLUGINS:
                raise serializers.ValidationError(
                    _("Plugin {} is not installed in pulp3.".format(plugin)))
            try:
                db.command("collstats", plugin_migrator.pulp2_collection)
            except OperationFailure:
                raise serializers.ValidationError(
                    _("Plugin {} is not installed in pulp2.".format(plugin)))
        data["plan"] = loaded_plan
        return data