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
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)
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
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)
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