Skip to content

Commit

Permalink
Add one shot upload functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthias Dellweg committed Sep 4, 2019
1 parent ec1038f commit 20cd60d
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGES/5391.feature
@@ -0,0 +1 @@
Add oneshot upload functionality for deb type packages.
1 change: 1 addition & 0 deletions pulp_deb/app/serializers/__init__.py
Expand Up @@ -16,3 +16,4 @@
)

from .remote_serializers import DebRemoteSerializer
from .upload_serializers import OneShotUploadSerializer
27 changes: 27 additions & 0 deletions pulp_deb/app/serializers/upload_serializers.py
@@ -0,0 +1,27 @@
from gettext import gettext as _

from rest_framework.serializers import FileField, HyperlinkedRelatedField, Serializer
from pulpcore.plugin.models import Artifact, Repository


class OneShotUploadSerializer(Serializer):
"""
A serializer for the One Shot Upload API.
"""

repository = HyperlinkedRelatedField(
help_text=_("A URI of the repository."),
required=False,
queryset=Repository.objects.all(),
view_name="repositories-detail",
)
file = FileField(help_text=_("The deb file."), required=True)

def validate(self, data):
"""
Validate uploaded file, prepare artifact and collect shared resources.
"""
data = super().validate(data)
data["filename"] = data["file"].name
data["artifact"] = Artifact.init_and_validate(data["file"])
return data
1 change: 1 addition & 0 deletions pulp_deb/app/tasks/__init__.py
@@ -1,3 +1,4 @@
# flake8: noqa
from .publishing import publish, publish_verbatim
from .synchronizing import synchronize
from .upload import one_shot_upload
60 changes: 60 additions & 0 deletions pulp_deb/app/tasks/upload.py
@@ -0,0 +1,60 @@
import logging
from gettext import gettext as _

from debian import debfile

from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist

from pulpcore.plugin.models import Artifact, ContentArtifact, Repository, RepositoryVersion
from pulpcore.app.models.task import CreatedResource

from pulp_deb.app.models import Package


log = logging.getLogger(__name__)


def one_shot_upload(artifact_pk, repository_pk=None):
"""
Create a Package from an uploaded file and attach it to a Repository if provided.
Args:
artifact_pk (str): Create a Package from this artifact.
Optional:
repository_pk (str): Insert the Package into this Repository.
"""
artifact = Artifact.objects.get(pk=artifact_pk)
repository = Repository.objects.get(pk=repository_pk) if repository_pk else None
log.debug(
_("Uploading deb package: artifact={artifact}, repository={repo}").format(
artifact=artifact, repo=repository
)
)

package_paragraph = debfile.DebFile(fileobj=artifact.file).debcontrol()
package_dict = Package.from822(package_paragraph)
package_dict["sha256"] = artifact.sha256
package = Package(**package_dict)
package.relative_path = package.filename
try:
package = Package.objects.get(sha256=artifact.sha256, relative_path=package.relative_path)
except ObjectDoesNotExist:
with transaction.atomic():
package.save()

ContentArtifact.objects.create(
artifact=artifact, content=package, relative_path=package.relative_path
)

resource = CreatedResource(content_object=package)
resource.save()

if repository:
content_to_add = Package.objects.filter(pk=package.pk)

# create new repo version with uploaded package
with RepositoryVersion.create(repository) as new_version:
new_version.add_content(content_to_add)
6 changes: 6 additions & 0 deletions pulp_deb/app/urls.py
@@ -0,0 +1,6 @@
from django.conf.urls import url

from .viewsets import OneShotUploadViewSet


urlpatterns = [url(r"deb/upload/$", OneShotUploadViewSet.as_view({"post": "create"}))]
59 changes: 59 additions & 0 deletions pulp_deb/app/viewsets.py
@@ -1,8 +1,12 @@
from gettext import gettext as _ # noqa

from django.db.utils import IntegrityError
from drf_yasg.utils import swagger_auto_schema
from rest_framework.decorators import action
from rest_framework.parsers import FormParser, MultiPartParser
from rest_framework.viewsets import ViewSet

from pulpcore.plugin.models import Artifact
from pulpcore.plugin.serializers import (
AsyncOperationResponseSerializer,
RepositorySyncURLSerializer,
Expand Down Expand Up @@ -120,6 +124,61 @@ class InstallerPackageViewSet(ContentViewSet):
serializer_class = serializers.InstallerPackageSerializer


class OneShotUploadViewSet(ViewSet):
"""
ViewSet for One Shot Deb Upload.
Args:
file@: package to upload
Optional:
repository: repository to update
"""

serializer_class = serializers.OneShotUploadSerializer
parser_classes = (MultiPartParser, FormParser)

@swagger_auto_schema(
operation_description="Create an artifact and trigger an asynchronous"
"task to create Deb content from it, optionally"
"create new repository version.",
operation_summary="Upload a package",
operation_id="upload_deb_package",
request_body=serializers.OneShotUploadSerializer,
responses={202: AsyncOperationResponseSerializer},
)
def create(self, request):
"""
Upload a Deb package.
"""
serializer = serializers.OneShotUploadSerializer(
data=request.data, context={"request": request}
)
serializer.is_valid(raise_exception=True)
artifact = serializer.validated_data["artifact"]
repository = serializer.validated_data.get("repository")

try:
artifact.save()
except IntegrityError:
# if artifact already exists, let's use it
artifact = Artifact.objects.get(sha256=artifact.sha256)

shared_resources = [artifact]
if repository:
shared_resources.append(repository)

async_result = enqueue_with_reservation(
tasks.one_shot_upload,
shared_resources,
kwargs={
"artifact_pk": artifact.pk,
"repository_pk": repository.pk if repository else None,
},
)
return OperationPostponedResponse(async_result, request)


class DebRemoteViewSet(RemoteViewSet):
"""
A ViewSet for DebRemote.
Expand Down

0 comments on commit 20cd60d

Please sign in to comment.