Beispiel #1
0
    def extract_pk(uri):
        """
        Resolve a resource URI to a simple PK value.

        Provides a means to resolve an href passed in a POST body to a primary key.
        Doesn't assume anything about whether the resource corresponding to the URI
        passed in actually exists.

        Note:
            Cannot be used with nested URIs where the PK of the final resource is not present.
            e.g. RepositoryVersion URI consists of repository PK and version number - no
            RepositoryVersion PK is present within the URI.

        Args:
            uri (str): A resource URI.

        Returns:
            primary_key (uuid.uuid4): The primary key of the resource extracted from the URI.

        Raises:
            rest_framework.exceptions.ValidationError: on invalid URI.
        """
        try:
            match = resolve(urlparse(uri).path)
        except Resolver404:
            raise DRFValidationError(detail=_("URI not valid: {u}").format(
                u=uri))

        try:
            return match.kwargs["pk"]
        except KeyError:
            raise DRFValidationError(
                "URI does not contain an unqualified resource PK")
Beispiel #2
0
    def get_resource(uri, model=None):
        """
        Resolve a resource URI to an instance of the resource.

        Provides a means to resolve an href passed in a POST body to an
        instance of the resource.

        Args:
            uri (str): A resource URI.
            model (django.models.Model): A model class. If not provided, the method automatically
                determines the used model from the resource URI.

        Returns:
            django.models.Model: The resource fetched from the DB.

        Raises:
            rest_framework.exceptions.ValidationError: on invalid URI or resource not found.
        """
        try:
            match = resolve(urlparse(uri).path)
        except Resolver404:
            raise DRFValidationError(detail=_("URI not valid: {u}").format(u=uri))
        if "pk" in match.kwargs:
            kwargs = {"pk": match.kwargs["pk"]}
        else:
            kwargs = {}
            for key, value in match.kwargs.items():
                if key.endswith("_pk"):
                    kwargs["{}__pk".format(key[:-3])] = value
                else:
                    kwargs[key] = value

        if model is None:
            model = match.func.cls.queryset.model

        try:
            return model.objects.get(**kwargs)
        except model.MultipleObjectsReturned:
            raise DRFValidationError(
                detail=_("URI {u} matches more than one {m}.").format(
                    u=uri, m=model._meta.model_name
                )
            )
        except model.DoesNotExist:
            raise DRFValidationError(
                detail=_("URI {u} not found for {m}.").format(u=uri, m=model._meta.model_name)
            )
        except ValidationError:
            raise DRFValidationError(detail=_("ID invalid: {u}").format(u=kwargs["pk"]))
        except FieldError:
            raise DRFValidationError(
                detail=_("URI {u} is not a valid {m}.").format(u=uri, m=model._meta.model_name)
            )
Beispiel #3
0
    def sync(self, request, pk):
        """
        Dispatches a sync task.
        """
        repository = self.get_object()
        serializer = RpmRepositorySyncURLSerializer(data=request.data,
                                                    context={
                                                        "request": request,
                                                        "repository_pk": pk
                                                    })
        serializer.is_valid(raise_exception=True)
        remote = serializer.validated_data.get("remote", repository.remote)
        mirror = serializer.validated_data.get("mirror")
        sync_policy = serializer.validated_data.get("sync_policy")
        skip_types = serializer.validated_data.get("skip_types")
        optimize = serializer.validated_data.get("optimize")

        if not sync_policy:
            sync_policy = SYNC_POLICIES.ADDITIVE if not mirror else SYNC_POLICIES.MIRROR_COMPLETE

        # validate some invariants that involve repository-wide settings.
        if sync_policy in (SYNC_POLICIES.MIRROR_COMPLETE,
                           SYNC_POLICIES.MIRROR_CONTENT_ONLY):
            err_msg = (
                "Cannot use '{}' in combination with a 'mirror_complete' or "
                "'mirror_content_only' sync policy.")
            if repository.retain_package_versions > 0:
                raise DRFValidationError(
                    err_msg.format("retain_package_versions"))

        if sync_policy == SYNC_POLICIES.MIRROR_COMPLETE:
            err_msg = "Cannot use '{}' in combination with a 'mirror_complete' sync policy."
            if repository.autopublish:
                raise DRFValidationError(err_msg.format("autopublish"))
            if skip_types:
                raise DRFValidationError(err_msg.format("skip_types"))

        result = dispatch(
            tasks.synchronize,
            shared_resources=[remote],
            exclusive_resources=[repository],
            kwargs={
                "sync_policy": sync_policy,
                "remote_pk": str(remote.pk),
                "repository_pk": str(repository.pk),
                "skip_types": skip_types,
                "optimize": optimize,
            },
        )
        return OperationPostponedResponse(result, request)
Beispiel #4
0
    def sync(self, request, pk):
        """
        Dispatches a sync task.
        """
        repository = self.get_object()
        serializer = RpmRepositorySyncURLSerializer(
            data=request.data, context={"request": request, "repository_pk": pk}
        )
        serializer.is_valid(raise_exception=True)
        remote = serializer.validated_data.get("remote", repository.remote)
        mirror = serializer.validated_data.get("mirror")
        skip_types = serializer.validated_data.get("skip_types")
        optimize = serializer.validated_data.get("optimize")

        if repository.retain_package_versions > 0 and mirror:
            raise DRFValidationError("Cannot use 'retain_package_versions' with mirror-mode sync")

        result = enqueue_with_reservation(
            tasks.synchronize,
            [repository, remote],
            kwargs={
                "mirror": mirror,
                "remote_pk": remote.pk,
                "repository_pk": repository.pk,
                "skip_types": skip_types,
                "optimize": optimize,
            },
        )
        return OperationPostponedResponse(result, request)
Beispiel #5
0
    def get_resource(uri, model):
        """
        Resolve a resource URI to an instance of the resource.

        Provides a means to resolve an href passed in a POST body to an
        instance of the resource.

        Args:
            uri (str): A resource URI.
            model (django.models.Model): A model class.

        Returns:
            django.models.Model: The resource fetched from the DB.

        Raises:
            rest_framework.exceptions.ValidationError: on invalid URI or resource not found.
        """
        try:
            match = resolve(urlparse(uri).path)
        except Resolver404:
            raise DRFValidationError(detail=_('URI not valid: {u}').format(
                u=uri))
        if 'pk' in match.kwargs:
            kwargs = {'pk': match.kwargs['pk']}
        else:
            kwargs = {}
            for key, value in match.kwargs.items():
                if key.endswith('_pk'):
                    kwargs["{}__pk".format(key[:-3])] = value
                else:
                    kwargs[key] = value
        try:
            return model.objects.get(**kwargs)
        except model.MultipleObjectsReturned:
            raise DRFValidationError(
                detail=_('URI {u} matches more than one {m}.').format(
                    u=uri, m=model._meta.model_name))
        except model.DoesNotExist:
            raise DRFValidationError(detail=_('URI {u} not found for {m}.').
                                     format(u=uri, m=model._meta.model_name))
        except ValidationError:
            raise DRFValidationError(detail=_('ID invalid: {u}').format(
                u=kwargs['pk']))
        except FieldError:
            raise DRFValidationError(detail=_('URI {u} is not a valid {m}.').
                                     format(u=uri, m=model._meta.model_name))
Beispiel #6
0
    def filter(self, qs, value):
        """
        Args:
            qs (django.db.models.query.QuerySet): The Model queryset
            value (string): label search querry

        Returns:
            Queryset of the Models filtered by label(s)

        Raises:
            rest_framework.exceptions.ValidationError: on invalid search string
        """
        if value is None:
            # user didn't supply a value
            return qs

        for term in value.split(","):
            match = re.match(r"(!?[\w\s]+)(=|!=|~)?(.*)?", term)
            if not match:
                raise DRFValidationError(
                    _("Invalid search term: '{}'.").format(term))
            key, op, val = match.groups()

            if key.startswith("!") and op:
                raise DRFValidationError(
                    _("Cannot use an operator with '{}'.").format(key))

            if op == "=":
                labels = Label.objects.filter(key=key, value=val)
                qs = qs.filter(pulp_labels__in=labels)
            elif op == "!=":
                labels = Label.objects.filter(key=key).exclude(value=val)
                qs = qs.filter(pulp_labels__in=labels)
            elif op == "~":
                labels = Label.objects.filter(key=key, value__icontains=val)
                qs = qs.filter(pulp_labels__in=labels)
            else:
                # 'foo', '!foo'
                if key.startswith("!"):
                    labels = Label.objects.filter(key=key[1:])
                    qs = qs.exclude(pulp_labels__in=labels)
                else:
                    labels = Label.objects.filter(key=key)
                    qs = qs.filter(pulp_labels__in=labels)

        return qs
Beispiel #7
0
    def _check_author_link_permissions(self, serializer_row):
        """ Checks if legitimate to link to a resource

        We consider that legitimacy comes from having right to edit the
        resource we link to.
        """
        if (not self.model.has_author_direct_link()
                and not self.model.is_author_class()):
            referent_obj = self.model.get_directly_linked_obj(serializer_row)
            perm = self._get_owner_permission()
            if not perm.can_user_do(self.request.user, referent_obj, 'change'):
                raise DRFValidationError(
                    'You tried to link to a forbidden resource : {}'.format(
                        referent_obj))
Beispiel #8
0
    def _process_config(self, config):
        """
        Change the hrefs into pks within config.

        This method also implicitly validates that the hrefs map to objects and it returns a list of
        repos so that the task can lock on them.
        """
        result = []
        # exclusive use of the destination repos is needed since new repository versions are being
        # created, but source repos can be accessed in a read-only fashion in parallel, so long
        # as there are no simultaneous modifications.
        shared_repos = []
        exclusive_repos = []

        for entry in config:
            r = dict()
            source_version = NamedModelViewSet().get_resource(
                entry["source_repo_version"], RepositoryVersion)
            dest_repo = NamedModelViewSet().get_resource(
                entry["dest_repo"], RpmRepository)
            r["source_repo_version"] = source_version.pk
            r["dest_repo"] = dest_repo.pk
            shared_repos.append(source_version.repository)
            exclusive_repos.append(dest_repo)

            if "dest_base_version" in entry:
                try:
                    r["dest_base_version"] = dest_repo.versions.get(
                        number=entry["dest_base_version"]).pk
                except RepositoryVersion.DoesNotExist:
                    message = _(
                        "Version {version} does not exist for repository "
                        "'{repo}'.").format(version=entry["dest_base_version"],
                                            repo=dest_repo.name)
                    raise DRFValidationError(detail=message)

            if entry.get("content") is not None:
                r["content"] = []
                for c in entry["content"]:
                    r["content"].append(NamedModelViewSet().extract_pk(c))
            result.append(r)

        return result, shared_repos, exclusive_repos
Beispiel #9
0
    def _process_config(self, config):
        """
        Change the hrefs into pks within config.

        This method also implicitly validates that the hrefs map to objects and it returns a list of
        repos so that the task can lock on them.
        """
        result = []
        exclusive_resources = []
        shared_resources = []

        for entry in config:
            r = dict()
            source_version = NamedModelViewSet().get_resource(
                entry["source_repo_version"], RepositoryVersion
            )
            dest_repo = NamedModelViewSet().get_resource(entry["dest_repo"], AnsibleRepository)
            r["source_repo_version"] = source_version.pk
            r["dest_repo"] = dest_repo.pk
            exclusive_resources.append(dest_repo)
            shared_resources.append(source_version.repository)

            if "dest_base_version" in entry:
                try:
                    r["dest_base_version"] = dest_repo.versions.get(
                        number=entry["dest_base_version"]
                    ).pk
                except RepositoryVersion.DoesNotExist:
                    message = _(
                        "Version {version} does not exist for repository " "'{repo}'."
                    ).format(version=entry["dest_base_version"], repo=dest_repo.name)
                    raise DRFValidationError(detail=message)

            if entry.get("content") is not None:
                r["content"] = []
                for c in entry["content"]:
                    r["content"].append(NamedModelViewSet().extract_pk(c))
            result.append(r)

        return result, exclusive_resources, shared_resources
Beispiel #10
0
 def update(self, instance, validated_data, *args, **kwargs):
     try:
         return super().update(instance, validated_data, *args, **kwargs)
     except DjangoValidationError as e:
         raise DRFValidationError(e.error_list)
Beispiel #11
0
 def create(self, validated_data, *args, **kwargs):
     try:
         return super().create(validated_data, *args, **kwargs)
     except DjangoValidationError as e:
         raise DRFValidationError(e.error_list)