Exemple #1
0
    def run_validation(self, data):
        """
        Validates 'data' dict.

        Validates that all keys of 'data' are relative paths. Validates that all values of 'data'
        are URLs for an existing Artifact.

        Args:
            data (dict): A dict mapping relative paths inside the Content to the corresponding
                Artifact URLs.

        Returns:
            A dict mapping relative paths inside the Content to the corresponding Artifact
                instances.

        Raises:
            :class:`rest_framework.exceptions.ValidationError`: When one of the Artifacts does not
                exist or one of the paths is not a relative path.
        """
        ret = {}
        for relative_path, url in data.items():
            if os.path.isabs(relative_path):
                raise serializers.ValidationError(_("Relative path can't start with '/'. "
                                                    "{0}").format(relative_path))
            artifactfield = RelatedField(view_name='artifacts-detail',
                                         queryset=models.Artifact.objects.all(),
                                         source='*', initial=url)
            try:
                artifact = artifactfield.run_validation(data=url)
                ret[relative_path] = artifact
            except serializers.ValidationError as e:
                # Append the URL of missing Artifact to the error message
                e.detail[0] = "%s %s" % (e.detail[0], url)
                raise e
        return ret
Exemple #2
0
    def run_validation(self, data):
        """
        Validates 'data' dict.

        Validates that all keys of 'data' are relative paths. Validates that all values of 'data'
        are URLs for an existing Artifact.

        Args:
            data (dict): A dict mapping relative paths inside the Content to the corresponding
                Artifact URLs.

        Returns:
            A dict mapping relative paths inside the Content to the corresponding Artifact
                instances.

        Raises:
            :class:`rest_framework.exceptions.ValidationError`: When one of the Artifacts does not
                exist or one of the paths is not a relative path.
        """
        ret = {}
        for relative_path, url in data.items():
            if os.path.isabs(relative_path):
                raise serializers.ValidationError(_("Relative path can't start with '/'. "
                                                    "{0}").format(relative_path))
            artifactfield = RelatedField(view_name='artifacts-detail',
                                         queryset=models.Artifact.objects.all(),
                                         source='*', initial=url)
            try:
                artifact = artifactfield.run_validation(data=url)
                ret[relative_path] = artifact
            except serializers.ValidationError as e:
                # Append the URL of missing Artifact to the error message
                e.detail[0] = "%s %s" % (e.detail[0], url)
                raise e
        return ret
Exemple #3
0
class TaskSerializer(ModelSerializer):
    _href = IdentityField(view_name='tasks-detail')
    state = serializers.CharField(
        help_text=_("The current state of the task. The possible values include:"
                    " 'waiting', 'skipped', 'running', 'completed', 'failed' and 'canceled'."),
        read_only=True
    )
    started_at = serializers.DateTimeField(
        help_text=_("Timestamp of the when this task started execution."),
        read_only=True
    )
    finished_at = serializers.DateTimeField(
        help_text=_("Timestamp of the when this task stopped execution."),
        read_only=True
    )
    non_fatal_errors = serializers.JSONField(
        help_text=_("A JSON Object of non-fatal errors encountered during the execution of this "
                    "task."),
        read_only=True
    )
    error = serializers.JSONField(
        help_text=_("A JSON Object of a fatal error encountered during the execution of this "
                    "task."),
        read_only=True
    )
    worker = RelatedField(
        help_text=_("The worker associated with this task."
                    " This field is empty if a worker is not yet assigned."),
        read_only=True,
        view_name='workers-detail'
    )
    parent = RelatedField(
        help_text=_("The parent task that spawned this task."),
        read_only=True,
        view_name='tasks-detail'
    )
    spawned_tasks = RelatedField(
        help_text=_("Any tasks spawned by this task."),
        many=True,
        read_only=True,
        view_name='tasks-detail'
    )
    progress_reports = ProgressReportSerializer(
        many=True,
        read_only=True
    )
    created_resources = CreatedResourceSerializer(
        help_text=_('Resources created by this task.'),
        many=True,
        read_only=True,
        view_name='None'  # This is a polymorphic field. The serializer does not need a view name.
    )

    class Meta:
        model = models.Task
        fields = ModelSerializer.Meta.fields + ('state', 'started_at', 'finished_at',
                                                'non_fatal_errors', 'error', 'worker', 'parent',
                                                'spawned_tasks', 'progress_reports',
                                                'created_resources')
Exemple #4
0
class RepositoryVersionDistributionSerializer(BaseDistributionSerializer):
    repository = RelatedField(
        required=False,
        help_text=_('The latest RepositoryVersion for this Repository will be served.'),
        queryset=models.Repository.objects.all(),
        view_name='repositories-detail',
        allow_null=True
    )
    repository_version = NestedRelatedField(
        required=False,
        help_text=_('RepositoryVersion to be served'),
        queryset=models.RepositoryVersion.objects.exclude(complete=False),
        view_name='versions-detail',
        allow_null=True,
        lookup_field='number',
        parent_lookup_kwargs={'repository_pk': 'repository__pk'},
    )

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

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

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

        return data
Exemple #5
0
class ExportSerializer(ModelSerializer):
    """
    Base serializer for Exports.
    """
    pulp_href = ExportIdentityField()

    task = RelatedField(
        help_text=_('A URI of the task that ran the Export.'),
        queryset=models.Task.objects.all(),
        view_name='tasks-detail',
    )

    exported_resources = ExportedResourcesSerializer(
        help_text=_('Resources that were exported.'),
        read_only=True,
        many=True,
    )

    params = serializers.JSONField(
        help_text=_(
            'Any additional parameters that were used to create the export.'),
        required=False,
    )

    class Meta:
        model = models.Export
        fields = ModelSerializer.Meta.fields + ('task', 'exported_resources',
                                                'params')
Exemple #6
0
class ProgressReportSerializer(ModelSerializer):

    message = serializers.CharField(
        help_text=_("The message shown to the user for the progress report."),
        read_only=True)
    state = serializers.CharField(help_text=_(
        "The current state of the progress report. The possible values are:"
        " 'waiting', 'skipped', 'running', 'completed', 'failed' and 'canceled'."
        " The default is 'waiting'."),
                                  read_only=True)
    total = serializers.IntegerField(help_text=_(
        "The total count of items to be handled by the ProgressBar."),
                                     read_only=True)
    done = serializers.IntegerField(
        help_text=_("The count of items already processed. Defaults to 0."),
        read_only=True)
    suffix = serializers.CharField(
        help_text=_("The suffix to be shown with the progress report."),
        read_only=True,
        allow_blank=True)
    task = RelatedField(
        help_text=_("The task associated with this progress report."),
        read_only=True,
        view_name='tasks-detail')

    class Meta:
        model = models.ProgressReport
        # this serializer is meant to be nested inside Task serializer,
        # so it will not have its own endpoint, that's why
        # we need to explicitly define fields to exclude '_href' field.
        fields = ('message', 'state', 'total', 'done', 'suffix', 'task')
Exemple #7
0
class ExportSerializer(ModelSerializer):
    """
    Base serializer for Exports.
    """

    pulp_href = ExportIdentityField()

    task = RelatedField(
        help_text=_("A URI of the task that ran the Export."),
        queryset=models.Task.objects.all(),
        view_name="tasks-detail",
        required=False,
        allow_null=True,
    )

    exported_resources = ExportedResourceField(
        help_text=_("Resources that were exported."),
        many=True,
        read_only=True,
        view_name=
        "None",  # This is a polymorphic field. The serializer does not need a view name.
    )

    params = serializers.JSONField(
        help_text=_(
            "Any additional parameters that were used to create the export."),
        read_only=True,
    )

    class Meta:
        model = models.Export
        fields = ModelSerializer.Meta.fields + ("task", "exported_resources",
                                                "params")
Exemple #8
0
    def run_validation(self, data):
        """
        Validates 'data' dict.

        Validates that all keys of 'data' are relative paths. Validates that all values of 'data'
        are URLs for an existing Artifact.

        Args:
            data (dict): A dict mapping relative paths inside the Content to the corresponding
                Artifact URLs.

        Returns:
            A dict mapping relative paths inside the Content to the corresponding Artifact
                instances.

        Raises:
            :class:`rest_framework.exceptions.ValidationError`: When one of the Artifacts does not
                exist or one of the paths is not a relative path or the field is missing.
        """
        ret = {}
        if data is empty:
            raise serializers.ValidationError(
                _("artifacts field must be specified."))
        for relative_path, url in data.items():
            relative_path_validator(relative_path)
            artifactfield = RelatedField(
                view_name="artifacts-detail",
                queryset=models.Artifact.objects.all(),
                source="*",
                initial=url,
            )
            try:
                artifact = artifactfield.run_validation(data=url)
                ret[relative_path] = artifact
            except serializers.ValidationError as e:
                # Append the URL of missing Artifact to the error message
                e.detail[0] = "%s %s" % (e.detail[0], url)
                raise e
        return ret
Exemple #9
0
class PublicationSerializer(MasterModelSerializer):
    _href = DetailIdentityField()
    repository_version = NestedRelatedField(
        view_name='versions-detail',
        lookup_field='number',
        parent_lookup_kwargs={'repository_pk': 'repository__pk'},
        queryset=models.RepositoryVersion.objects.all(),
        required=False,
    )
    repository = RelatedField(
        help_text=_('A URI of the repository to be published.'),
        required=False,
        label=_('Repository'),
        queryset=models.Repository.objects.all(),
        view_name='repositories-detail',
        write_only=True
    )

    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 = models.RepositoryVersion.latest(repository)
            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 = MasterModelSerializer.Meta.fields + (
            'publisher',
            'repository_version',
            'repository'
        )
Exemple #10
0
class ImportSerializer(ModelSerializer):
    """Serializer for Imports."""
    pulp_href = ImportIdentityField()

    task = RelatedField(
        help_text=_('A URI of the Task that ran the Import.'),
        queryset=models.Task.objects.all(),
        view_name='tasks-detail',
    )

    params = serializers.JSONField(
        help_text=_('Any parameters that were used to create the import.'), )

    class Meta:
        model = models.Importer
        fields = ModelSerializer.Meta.fields + ('task', 'params')
Exemple #11
0
class WorkerSerializer(ModelSerializer):
    pulp_href = IdentityField(view_name="workers-detail")

    name = serializers.CharField(help_text=_("The name of the worker."),
                                 read_only=True)
    last_heartbeat = serializers.DateTimeField(help_text=_(
        "Timestamp of the last time the worker talked to the service."),
                                               read_only=True)
    current_task = RelatedField(
        help_text=_(
            "The task this worker is currently executing, or empty if the worker is not "
            "currently assigned to a task."),
        read_only=True,
        view_name="tasks-detail",
    )

    class Meta:
        model = models.Worker
        fields = ModelSerializer.Meta.fields + ("name", "last_heartbeat",
                                                "current_task")
Exemple #12
0
class TaskSerializer(ModelSerializer):
    pulp_href = IdentityField(view_name="tasks-detail")
    state = serializers.CharField(
        help_text=_(
            "The current state of the task. The possible values include:"
            " 'waiting', 'skipped', 'running', 'completed', 'failed', 'canceled' and 'canceling'."
        ),
        read_only=True,
    )
    name = serializers.CharField(help_text=_("The name of task."))
    logging_cid = serializers.CharField(
        help_text=_("The logging correlation id associated with this task")
    )
    started_at = serializers.DateTimeField(
        help_text=_("Timestamp of the when this task started execution."), read_only=True
    )
    finished_at = serializers.DateTimeField(
        help_text=_("Timestamp of the when this task stopped execution."), read_only=True
    )
    error = serializers.DictField(
        child=serializers.JSONField(),
        help_text=_(
            "A JSON Object of a fatal error encountered during the execution of this task."
        ),
        read_only=True,
    )
    worker = RelatedField(
        help_text=_(
            "The worker associated with this task."
            " This field is empty if a worker is not yet assigned."
        ),
        read_only=True,
        view_name="workers-detail",
    )
    parent_task = RelatedField(
        help_text=_("The parent task that spawned this task."),
        read_only=True,
        view_name="tasks-detail",
    )
    child_tasks = RelatedField(
        help_text=_("Any tasks spawned by this task."),
        many=True,
        read_only=True,
        view_name="tasks-detail",
    )
    task_group = RelatedField(
        help_text=_("The task group that this task is a member of."),
        read_only=True,
        view_name="task-groups-detail",
    )
    progress_reports = ProgressReportSerializer(many=True, read_only=True)
    created_resources = CreatedResourceSerializer(
        help_text=_("Resources created by this task."),
        many=True,
        read_only=True,
        view_name="None",  # This is a polymorphic field. The serializer does not need a view name.
    )
    reserved_resources_record = serializers.ListField(
        child=serializers.CharField(),
        help_text=_("A list of resources required by that task."),
        read_only=True,
    )

    class Meta:
        model = models.Task
        fields = ModelSerializer.Meta.fields + (
            "state",
            "name",
            "logging_cid",
            "started_at",
            "finished_at",
            "error",
            "worker",
            "parent_task",
            "child_tasks",
            "task_group",
            "progress_reports",
            "created_resources",
            "reserved_resources_record",
        )
Exemple #13
0
class DistributionSerializer(ModelSerializer):
    _href = IdentityField(
        view_name='distributions-detail'
    )
    name = serializers.CharField(
        help_text=_('A unique distribution name. Ex, `rawhide` and `stable`.'),
        validators=[validators.MaxLengthValidator(
            models.Distribution._meta.get_field('name').max_length,
            message=_('Distribution name length must be less than {} characters').format(
                models.Distribution._meta.get_field('name').max_length
            )),
            UniqueValidator(queryset=models.Distribution.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.Distribution._meta.get_field('base_path').max_length,
            message=_('Distribution base_path length must be less than {} characters').format(
                models.Distribution._meta.get_field('base_path').max_length
            )),
            UniqueValidator(queryset=models.Distribution.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.Publisher.objects.all(),
        allow_null=True
    )
    content_guard = DetailRelatedField(
        required=False,
        help_text=_('An optional content-guard.'),
        queryset=models.ContentGuard.objects.all(),
        allow_null=True
    )
    publication = RelatedField(
        required=False,
        help_text=_('The publication being served as defined by this distribution'),
        queryset=models.Publication.objects.exclude(complete=False),
        view_name='publications-detail',
        allow_null=True
    )
    repository = serializers.HyperlinkedRelatedField(
        required=False,
        help_text=_('Publications created by this repository and publisher are automatically'
                    'served as defined by this distribution'),
        queryset=models.Repository.objects.all(),
        view_name='repositories-detail',
        allow_null=True
    )
    base_url = BaseURLField(
        source='base_path', read_only=True,
        help_text=_('The URL for accessing the publication as defined by this distribution.')
    )

    class Meta:
        model = models.Distribution
        fields = ModelSerializer.Meta.fields + (
            'name',
            'base_path',
            'publisher',
            'publication',
            'base_url',
            '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.Distribution.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):
        self._validate_relative_path(path)
        return self._validate_path_overlap(path)

    def validate(self, data):
        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
Exemple #14
0
class BaseDistributionSerializer(ModelSerializer):
    _href = IdentityField(view_name='distributions-detail')
    name = serializers.CharField(
        help_text=_('A unique distribution name. Ex, `rawhide` and `stable`.'),
        validators=[
            validators.MaxLengthValidator(
                models.Distribution._meta.get_field('name').max_length,
                message=_(
                    'Distribution name length must be less than {} characters'
                ).format(
                    models.Distribution._meta.get_field('name').max_length)),
            UniqueValidator(queryset=models.Distribution.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.Distribution._meta.get_field('base_path').max_length,
                message=
                _('Distribution base_path length must be less than {} characters'
                  ).format(
                      models.Distribution._meta.get_field(
                          'base_path').max_length)),
            UniqueValidator(queryset=models.Distribution.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.Publisher.objects.all(),
        allow_null=True)
    content_guard = DetailRelatedField(
        required=False,
        help_text=_('An optional content-guard.'),
        queryset=models.ContentGuard.objects.all(),
        allow_null=True)
    publication = RelatedField(
        required=False,
        help_text=_(
            'The publication being served as defined by this distribution'),
        queryset=models.Publication.objects.exclude(complete=False),
        view_name='publications-detail',
        allow_null=True)
    repository = serializers.HyperlinkedRelatedField(
        required=False,
        help_text=_(
            'Publications created by this repository and publisher are automatically'
            'served as defined by this distribution'),
        queryset=models.Repository.objects.all(),
        view_name='repositories-detail',
        allow_null=True)
    remote = DetailRelatedField(
        required=False,
        help_text=
        _('Remote that can be used to fetch content when using pull-through caching.'
          ),
        queryset=models.Remote.objects.all(),
        allow_null=True)

    class Meta:
        fields = ModelSerializer.Meta.fields + (
            'name',
            'publisher',
            'publication',
            'repository',
            'content_guard',
            'remote',
        )

    def validate(self, data):
        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