Esempio n. 1
0
    def _save_content_artifact(self, download_result, content_artifact):
        """
        Create/Get an Artifact and associate it to a ContentArtifact.

        Create (or get if already existing) an :class:`~pulpcore.plugin.models.Artifact`
        based on the `download_result` and associate it to the given `content_artifact`. Both
        the created artifact and the updated content_artifact are saved to the DB.

        Plugin-writers may overide this method if their content module requires
        additional/different steps for saving.

        Args:
            download_result (:class:`~pulpcore.plugin.download.DownloadResult`: The
                DownloadResult for the downloaded artifact.

            content_artifact (:class:`~pulpcore.plugin.models.ContentArtifact`): The
                ContentArtifact to associate the Artifact with.

        Returns:
            The associated :class:`~pulpcore.plugin.models.Artifact`.
        """
        artifact = Artifact(
            **download_result.artifact_attributes,
            file=download_result.path
        )
        with transaction.atomic():
            try:
                with transaction.atomic():
                    artifact.save()
            except IntegrityError:
                artifact = Artifact.objects.get(artifact.q())
            content_artifact.artifact = artifact
            content_artifact.save()
        return artifact
Esempio n. 2
0
    def post(self, request, path):
        """
        Queues a task that creates a new Collection from an uploaded artifact.
        """
        distro = get_object_or_404(AnsibleDistribution, base_path=path)
        serializer = GalaxyCollectionUploadSerializer(
            data=request.data, context={"request": request})
        serializer.is_valid(raise_exception=True)

        expected_digests = {"sha256": serializer.validated_data["sha256"]}
        artifact = Artifact.init_and_validate(
            serializer.validated_data["file"],
            expected_digests=expected_digests)
        artifact.save()

        locks = [str(artifact.pk)]
        kwargs = {"artifact_pk": artifact.pk}
        if distro.repository:
            locks.append(distro.repository)
            kwargs["repository_pk"] = distro.repository.pk

        async_result = enqueue_with_reservation(import_collection,
                                                locks,
                                                kwargs=kwargs)
        return OperationPostponedResponse(async_result, request)
Esempio n. 3
0
    async def _stream_content_artifact(self, request, response,
                                       content_artifact):
        """
        Stream and optionally save a ContentArtifact by requesting it using the associated remote.

        Args:
            request(:class:`~aiohttp.web.Request`): The request to prepare a response for.
            response (:class:`~aiohttp.web.StreamResponse`): The response to stream data to.
            content_artifact (:class:`~pulpcore.plugin.models.ContentArtifact`): The ContentArtifact
                to fetch and then stream back to the client
        """
        remote_artifact = content_artifact.remoteartifact_set.get()
        remote = remote_artifact.remote.cast()

        async def handle_headers(headers):
            for name, value in headers.items():
                if name.lower() in HOP_BY_HOP_HEADERS:
                    continue
                response.headers[name] = value
            await response.prepare(request)

        async def handle_data(data):
            await response.write(data)
            if remote.policy != Remote.STREAMED:
                await original_handle_data(data)

        async def finalize():
            if remote.policy != Remote.STREAMED:
                await original_finalize()

        downloader = remote.get_downloader(
            remote_artifact=remote_artifact,
            headers_ready_callback=handle_headers)
        original_handle_data = downloader.handle_data
        downloader.handle_data = handle_data
        original_finalize = downloader.finalize
        downloader.finalize = finalize
        download_result = await downloader.run()
        if remote.policy != Remote.STREAMED:
            with transaction.atomic():
                new_artifact = Artifact(**download_result.artifact_attributes,
                                        file=download_result.path)
                new_artifact.save()
                content_artifact.artifact = new_artifact
                content_artifact.save()
        await response.write_eof()
        return response
Esempio n. 4
0
    def post(self, request, *args, **kwargs):
        """
        Queues a task that creates a new Collection from an uploaded artifact.
        """
        serializer = GalaxyCollectionUploadSerializer(
            data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)

        expected_digests = {'sha256': serializer.validated_data['sha256']}
        artifact = Artifact.init_and_validate(
            serializer.validated_data['file'],
            expected_digests=expected_digests)
        artifact.save()

        async_result = enqueue_with_reservation(import_collection,
                                                [str(artifact.pk)],
                                                kwargs={
                                                    'artifact_pk': artifact.pk,
                                                })
        return OperationPostponedResponse(async_result, request)
Esempio n. 5
0
    def _save_artifact(self, download_result, remote_artifact):
        """
        Create/Get an Artifact and associate it to a RemoteArtifact and/or ContentArtifact.

        Create (or get if already existing) an :class:`~pulpcore.plugin.models.Artifact`
        based on the `download_result` and associate it to the `content_artifact` of the given
        `remote_artifact`. Both the created artifact and the updated content_artifact are saved to
        the DB.  The `remote_artifact` is also saved for the pull-through caching use case.

        Plugin-writers may overide this method if their content module requires
        additional/different steps for saving.

        Args:
            download_result (:class:`~pulpcore.plugin.download.DownloadResult`: The
                DownloadResult for the downloaded artifact.

            remote_artifact (:class:`~pulpcore.plugin.models.RemoteArtifact`): The
                RemoteArtifact to associate the Artifact with.

        Returns:
            The associated :class:`~pulpcore.plugin.models.Artifact`.
        """
        content_artifact = remote_artifact.content_artifact
        remote = remote_artifact.remote
        artifact = Artifact(**download_result.artifact_attributes, file=download_result.path)
        with transaction.atomic():
            try:
                with transaction.atomic():
                    artifact.save()
            except IntegrityError:
                artifact = Artifact.objects.get(artifact.q())
            update_content_artifact = True
            if content_artifact._state.adding:
                # This is the first time pull-through content was requested.
                rel_path = content_artifact.relative_path
                c_type = remote.get_remote_artifact_content_type(rel_path)
                content = c_type.init_from_artifact_and_relative_path(artifact, rel_path)
                try:
                    with transaction.atomic():
                        content.save()
                        content_artifact.content = content
                        content_artifact.save()
                except IntegrityError:
                    # There is already content for this Artifact
                    content = c_type.objects.get(content.q())
                    artifacts = content._artifacts
                    if artifact.sha256 != artifacts[0].sha256:
                        raise RuntimeError(
                            "The Artifact downloaded during pull-through does not "
                            "match the Artifact already stored for the same "
                            "content."
                        )
                    content_artifact = ContentArtifact.objects.get(content=content)
                    update_content_artifact = False
                try:
                    with transaction.atomic():
                        remote_artifact.content_artifact = content_artifact
                        remote_artifact.save()
                except IntegrityError:
                    # Remote artifact must have already gotten saved during a parallel request
                    log.info("RemoteArtifact already exists.")
            if update_content_artifact:
                content_artifact.artifact = artifact
                content_artifact.save()
        return artifact