Skip to content

Commit

Permalink
Refactor CollectionVersion Upload to use pulpcore machinery
Browse files Browse the repository at this point in the history
fixes: #1175
  • Loading branch information
gerrod3 committed Aug 29, 2022
1 parent bde6984 commit a48903d
Show file tree
Hide file tree
Showing 16 changed files with 524 additions and 220 deletions.
1 change: 1 addition & 0 deletions CHANGES/1175.bugfix
@@ -0,0 +1 @@
Properly return 400 error when trying to create/upload a duplicate Collection.
1 change: 1 addition & 0 deletions CHANGES/1175.feature
@@ -0,0 +1 @@
An existing artifact or upload object can now be used to create a Collection.
5 changes: 5 additions & 0 deletions CHANGES/1176.removal
@@ -0,0 +1,5 @@
Renamed CollectionVersion upload fields [namespace, name, version] to expected_[namespace, name, version].

Deprecated /ansible/collections/ upload endpoint. Use /pulp/api/v3/content/ansible/collection_versions/ instead.

Deprecated Galaxy V2 Collection upload endpoint. Use Galaxy V3 Collection Artifact upload endpoint instead.
6 changes: 6 additions & 0 deletions pulp_ansible/app/galaxy/mixins.py
Expand Up @@ -19,3 +19,9 @@ def _dispatch_import_collection_task(self, temp_file_pk, repository=None, **kwar
kwargs["repository_pk"] = repository.pk

return dispatch(import_collection, exclusive_resources=locks, kwargs=kwargs)

def get_deferred_context(self, request):
context = {}
if "file" in request.data:
context["filename"] = request.data["file"].name
return context
8 changes: 8 additions & 0 deletions pulp_ansible/app/galaxy/serializers.py
Expand Up @@ -6,6 +6,7 @@
from rest_framework.reverse import reverse
from rest_framework import serializers

from pulpcore.plugin.models import Artifact
from pulp_ansible.app.models import Collection, CollectionVersion, Role
from pulp_ansible.app.galaxy.v3.serializers import CollectionMetadataSerializer

Expand Down Expand Up @@ -187,3 +188,10 @@ class GalaxyCollectionUploadSerializer(serializers.Serializer):
file = serializers.FileField(
help_text=_("The file containing the Artifact binary data."), required=True
)

def validate(self, data):
"""Ensure duplicate artifact isn't uploaded."""
sha256 = data["file"].hashers["sha256"].hexdigest()
artifact = Artifact.objects.filter(sha256=sha256).first()
if artifact:
raise serializers.ValidationError(_("Artifact already exists"))
59 changes: 23 additions & 36 deletions pulp_ansible/app/galaxy/v3/views.py
Expand Up @@ -26,10 +26,13 @@
from rest_framework.exceptions import NotFound
from rest_framework import status

from pulpcore.plugin.exceptions import DigestValidationError
from pulpcore.plugin.models import PulpTemporaryFile, Content
from pulpcore.plugin.models import Content
from pulpcore.plugin.serializers import AsyncOperationResponseSerializer
from pulpcore.plugin.viewsets import BaseFilterSet, OperationPostponedResponse
from pulpcore.plugin.viewsets import (
BaseFilterSet,
OperationPostponedResponse,
SingleArtifactContentUploadViewSet,
)
from pulpcore.plugin.tasking import add_and_remove, dispatch

from pulp_ansible.app.galaxy.v3.exceptions import ExceptionHandlerMixin
Expand All @@ -50,8 +53,9 @@
CollectionImport,
)
from pulp_ansible.app.serializers import (
CollectionOneShotSerializer,
CollectionImportDetailSerializer,
CollectionOneShotSerializer,
CollectionVersionUploadSerializer,
)

from pulp_ansible.app.galaxy.mixins import UploadGalaxyCollectionMixin
Expand Down Expand Up @@ -454,13 +458,14 @@ def urlpattern(*args, **kwargs):


class CollectionUploadViewSet(
ExceptionHandlerMixin, viewsets.GenericViewSet, UploadGalaxyCollectionMixin
ExceptionHandlerMixin, UploadGalaxyCollectionMixin, SingleArtifactContentUploadViewSet
):
"""
ViewSet for Collection Uploads.
"""

serializer_class = CollectionOneShotSerializer
queryset = CollectionVersion.objects.all()
serializer_class = CollectionVersionUploadSerializer
pulp_tag_name = "Pulp_Ansible: Artifacts Collections V3"

DEFAULT_ACCESS_POLICY = _PERMISSIVE_ACCESS_POLICY
Expand All @@ -481,44 +486,26 @@ def create(self, request, distro_base_path):
Dispatch a Collection creation task.
"""
distro = get_object_or_404(AnsibleDistribution, base_path=distro_base_path)
serializer = self.get_serializer(data=request.data, context={"request": request})
serializer.is_valid(raise_exception=True)

expected_digests = {}
if serializer.validated_data["sha256"]:
expected_digests["sha256"] = serializer.validated_data["sha256"]
try:
temp_file = PulpTemporaryFile.init_and_validate(
serializer.validated_data["file"],
expected_digests=expected_digests,
)
except DigestValidationError:
repo = distro.repository or distro.repository_version.repository
if repo is None:
raise serializers.ValidationError(
_("The provided sha256 value does not match the sha256 of the uploaded file.")
_("Distribution must have either repository or repository_version set")
)
# Check that invalid fields were not specified
serializer = CollectionOneShotSerializer(data=request.data)
serializer.is_valid(raise_exception=True)

temp_file.save()

kwargs = {}

if serializer.validated_data["expected_namespace"]:
kwargs["expected_namespace"] = serializer.validated_data["expected_namespace"]

if serializer.validated_data["expected_name"]:
kwargs["expected_name"] = serializer.validated_data["expected_name"]

if serializer.validated_data["expected_version"]:
kwargs["expected_version"] = serializer.validated_data["expected_version"]
request.data["repository"] = reverse("repositories-ansible/ansible-detail", args=[repo.pk])
async_response = super().create(request)
# Is there a href-to-pk util somewhere?
task = async_response.data["task"].rstrip("/").rsplit("/", maxsplit=1)[-1]

async_result = self._dispatch_import_collection_task(
temp_file.pk, distro.repository, **kwargs
)
CollectionImport.objects.create(task_id=async_result.pk)
CollectionImport.objects.create(task_id=task)

data = {
"task": reverse(
settings.ANSIBLE_URL_NAMESPACE + "collection-imports-detail",
kwargs={"pk": async_result.pk},
kwargs={"pk": task},
request=None,
)
}
Expand Down
2 changes: 2 additions & 0 deletions pulp_ansible/app/galaxy/views.py
Expand Up @@ -2,6 +2,7 @@

from django.conf import settings
from django.shortcuts import get_object_or_404, HttpResponse
from drf_spectacular.utils import extend_schema
from rest_framework import generics, pagination, response, views

from pulpcore.plugin.models import PulpTemporaryFile
Expand Down Expand Up @@ -167,6 +168,7 @@ def get_queryset(self):
"""
return Collection.objects.filter(versions__pk__in=self._distro_content).distinct()

@extend_schema(deprecated=True)
def post(self, request, path):
"""
Queues a task that creates a new Collection from an uploaded artifact.
Expand Down

0 comments on commit a48903d

Please sign in to comment.