diff --git a/README.rst b/README.rst index fe969e8d..04654172 100644 --- a/README.rst +++ b/README.rst @@ -177,25 +177,11 @@ Look at the new Repository Version created "number": 1 } -Create a ``docker`` Publisher ``baz`` ----------------------------------------------- - -``$ http POST http://localhost:8000/pulp/api/v3/publishers/docker/docker/ name=baz`` - -.. code:: json - - { - "_href": "/pulp/api/v3/publishers/docker/8ce1b34c-56c3-4ced-81b8-81e83b174fbc/", - ... - } - -``$ export PUBLISHER_HREF=$(http :8000/pulp/api/v3/publishers/docker/docker/ | jq -r '.results[] | select(.name == "baz") | ._href')`` - -Use the ``bar`` Publisher to create a Publication +Create a Publication ------------------------------------------------- -``$ http POST ':8000'$PUBLISHER_HREF'publish/' repository=$REPO_HREF`` +``$ http POST :8000/pulp/api/v3/docker/publications/ repository=$REPO_HREF`` .. code:: json @@ -203,7 +189,7 @@ Use the ``bar`` Publisher to create a Publication "task": "/pulp/api/v3/tasks/fd4cbecd-6c6a-4197-9cbe-4e45b0516309/" } -``$ export PUBLICATION_HREF=$(http :8000/pulp/api/v3/publications/ | jq -r --arg PUBLISHER_HREF "$PUBLISHER_HREF" '.results[] | select(.publisher==$PUBLISHER_HREF) | ._href')`` +``$ export PUBLICATION_HREF=$(http :8000/pulp/api/v3/publications/ | jq -r '.results[0] | ._href')`` Add a Docker Distribution to serve your publication --------------------------------------------------- diff --git a/pulp_docker/app/models.py b/pulp_docker/app/models.py index 6c6f04d5..a2546b8a 100644 --- a/pulp_docker/app/models.py +++ b/pulp_docker/app/models.py @@ -4,7 +4,7 @@ from django.db import models from pulpcore.plugin.download import DownloaderFactory -from pulpcore.plugin.models import BaseDistribution, Content, Remote, Publisher +from pulpcore.plugin.models import BaseDistribution, Content, Remote from . import downloaders @@ -210,16 +210,6 @@ class Meta: ) -class DockerPublisher(Publisher): - """ - A Publisher for DockerContent. - - Define any additional fields for your new publisher if needed. - """ - - TYPE = 'docker' - - class DockerRemote(Remote): """ A Remote for DockerContent. diff --git a/pulp_docker/app/serializers.py b/pulp_docker/app/serializers.py index 5f612e8d..a88925e0 100644 --- a/pulp_docker/app/serializers.py +++ b/pulp_docker/app/serializers.py @@ -10,7 +10,6 @@ BaseDistributionSerializer, DetailRelatedField, IdentityField, - PublisherSerializer, RemoteSerializer, SingleArtifactContentSerializer, ) @@ -174,25 +173,6 @@ class Meta: model = models.DockerRemote -class DockerPublisherSerializer(PublisherSerializer): - """ - A Serializer for DockerPublisher. - - Add any new fields if defined on DockerPublisher. - Similar to the example above, in DockerContentSerializer. - Additional validators can be added to the parent validators list - - For example:: - - class Meta: - validators = platform.PublisherSerializer.Meta.validators + [myValidator1, myValidator2] - """ - - class Meta: - fields = PublisherSerializer.Meta.fields - model = models.DockerPublisher - - class DockerDistributionSerializer(BaseDistributionSerializer): """ A serializer for DockerDistribution. diff --git a/pulp_docker/app/tasks/publishing.py b/pulp_docker/app/tasks/publishing.py index 79396571..c5db9ece 100644 --- a/pulp_docker/app/tasks/publishing.py +++ b/pulp_docker/app/tasks/publishing.py @@ -6,28 +6,20 @@ Publication ) -from pulp_docker.app.models import DockerPublisher - log = logging.getLogger(__name__) -def publish(publisher_pk, repository_version_pk): +def publish(repository_version_pk): """ - Use provided publisher to create a Publication based on a RepositoryVersion. + Create a Publication based on a RepositoryVersion. Args: - publisher_pk (str): Use the publish settings provided by this publisher. repository_version_pk (str): Create a publication from this repository version. """ - publisher = DockerPublisher.objects.get(pk=publisher_pk) repository_version = RepositoryVersion.objects.get(pk=repository_version_pk) - log.info(_('Publishing: repository={repo}, version={ver}, publisher={pub}').format( - repo=repository_version.repository.name, - ver=repository_version.number, - pub=publisher.name - )) + with Publication.create(repository_version, pass_through=True) as publication: + pass - with Publication.create(repository_version, publisher, pass_through=True) as publication: - log.info(_('Publication: {publication} created').format(publication=publication.pk)) + log.info(_('Publication: {publication} created').format(publication=publication.pk)) diff --git a/pulp_docker/app/viewsets.py b/pulp_docker/app/viewsets.py index 3d56ae2c..44a063bb 100644 --- a/pulp_docker/app/viewsets.py +++ b/pulp_docker/app/viewsets.py @@ -13,13 +13,14 @@ RepositoryPublishURLSerializer, RepositorySyncURLSerializer, ) + +from pulpcore.plugin.models import RepositoryVersion, Publication from pulpcore.plugin.tasking import enqueue_with_reservation from pulpcore.plugin.viewsets import ( ContentViewSet, NamedModelViewSet, RemoteViewSet, - OperationPostponedResponse, - PublisherViewSet) + OperationPostponedResponse,) from rest_framework.decorators import detail_route from rest_framework import mixins @@ -148,30 +149,24 @@ def sync(self, request, pk): return OperationPostponedResponse(result, request) -class DockerPublisherViewSet(PublisherViewSet): +class DockerPublicationViewSet(NamedModelViewSet, mixins.CreateModelMixin): """ - A ViewSet for DockerPublisher. + A ViewSet for Docker Publication. """ - endpoint_name = 'docker' - queryset = models.DockerPublisher.objects.all() - serializer_class = serializers.DockerPublisherSerializer + endpoint_name = 'docker/publications' + queryset = Publication.objects.all() + serializer_class = RepositoryPublishURLSerializer - # This decorator is necessary since a publish operation is asyncrounous and returns - # the id and href of the publish task. @swagger_auto_schema( - operation_description="Trigger an asynchronous task to publish content", + operation_description="Trigger an asynchronous task to create a docker publication", responses={202: AsyncOperationResponseSerializer} ) - @detail_route(methods=('post',), serializer_class=RepositoryPublishURLSerializer) - def publish(self, request, pk): + def create(self, request): """ - Publishes a repository. + Queues a task that publishes a new Docker Publication. - Either the ``repository`` or the ``repository_version`` fields can - be provided but not both at the same time. """ - publisher = self.get_object() serializer = RepositoryPublishURLSerializer( data=request.data, context={'request': request} @@ -179,13 +174,15 @@ def publish(self, request, pk): serializer.is_valid(raise_exception=True) repository_version = serializer.validated_data.get('repository_version') + # Safe because version OR repository is enforced by serializer. + if not repository_version: + repository = serializer.validated_data.get('repository') + repository_version = RepositoryVersion.latest(repository) + result = enqueue_with_reservation( tasks.publish, - [repository_version.repository, publisher], - kwargs={ - 'publisher_pk': str(publisher.pk), - 'repository_version_pk': str(repository_version.pk) - } + [repository_version.repository], + kwargs={'repository_version_pk': str(repository_version.pk)} ) return OperationPostponedResponse(result, request) diff --git a/pulp_docker/tests/functional/api/test_crud_publishers.py b/pulp_docker/tests/functional/api/test_crud_publishers.py deleted file mode 100644 index 7399aef8..00000000 --- a/pulp_docker/tests/functional/api/test_crud_publishers.py +++ /dev/null @@ -1,99 +0,0 @@ -# coding=utf-8 -"""Tests that CRUD content_unit publishers.""" -import unittest - -from requests.exceptions import HTTPError - -from pulp_smash import api, config -from pulp_smash.pulp3.constants import REPO_PATH -from pulp_smash.pulp3.utils import gen_repo, gen_publisher - -from pulp_docker.tests.functional.constants import DOCKER_PUBLISHER_PATH -from pulp_docker.tests.functional.utils import skip_if -from pulp_docker.tests.functional.utils import set_up_module as setUpModule # noqa:F401 - - -class CRUDPublishersTestCase(unittest.TestCase): - """CRUD publishers.""" - - @classmethod - def setUpClass(cls): - """Create class-wide variables. - - In order to create a publisher a repository has to be created first. - """ - cls.cfg = config.get_config() - cls.client = api.Client(cls.cfg, api.json_handler) - cls.publisher = {} - cls.repo = cls.client.post(REPO_PATH, gen_repo()) - - @classmethod - def tearDownClass(cls): - """Clean class-wide variable.""" - cls.client.delete(cls.repo['_href']) - - def test_01_create_publisher(self): - """Create a publisher.""" - body = gen_publisher() - type(self).publisher = self.client.post(DOCKER_PUBLISHER_PATH, body) - for key, val in body.items(): - with self.subTest(key=key): - self.assertEqual(self.publisher[key], val) - - @skip_if(bool, 'publisher', False) - def test_02_create_same_name(self): - """Try to create a second publisher with an identical name. - - See: `Pulp Smash #1055 - `_. - """ - body = gen_publisher() - body['name'] = self.publisher['name'] - with self.assertRaises(HTTPError): - self.client.post(DOCKER_PUBLISHER_PATH, body) - - @skip_if(bool, 'publisher', False) - def test_02_read_publisher(self): - """Read a publisher by its href.""" - publisher = self.client.get(self.publisher['_href']) - for key, val in self.publisher.items(): - with self.subTest(key=key): - self.assertEqual(publisher[key], val) - - @skip_if(bool, 'publisher', False) - def test_02_read_publishers(self): - """Read a publisher by its name.""" - page = self.client.get(DOCKER_PUBLISHER_PATH, params={ - 'name': self.publisher['name'] - }) - self.assertEqual(len(page['results']), 1) - for key, val in self.publisher.items(): - with self.subTest(key=key): - self.assertEqual(page['results'][0][key], val) - - @skip_if(bool, 'publisher', False) - def test_03_partially_update(self): - """Update a publisher using HTTP PATCH.""" - body = gen_publisher() - self.client.patch(self.publisher['_href'], body) - type(self).publisher = self.client.get(self.publisher['_href']) - for key, val in body.items(): - with self.subTest(key=key): - self.assertEqual(self.publisher[key], val) - - @skip_if(bool, 'publisher', False) - def test_04_fully_update(self): - """Update a publisher using HTTP PUT.""" - body = gen_publisher() - self.client.put(self.publisher['_href'], body) - type(self).publisher = self.client.get(self.publisher['_href']) - for key, val in body.items(): - with self.subTest(key=key): - self.assertEqual(self.publisher[key], val) - - @skip_if(bool, 'publisher', False) - def test_05_delete(self): - """Delete a publisher.""" - self.client.delete(self.publisher['_href']) - with self.assertRaises(HTTPError): - self.client.get(self.publisher['_href']) diff --git a/pulp_docker/tests/functional/api/test_publish.py b/pulp_docker/tests/functional/api/test_publish.py index 58ed627f..025ce493 100644 --- a/pulp_docker/tests/functional/api/test_publish.py +++ b/pulp_docker/tests/functional/api/test_publish.py @@ -2,18 +2,13 @@ """Tests that publish docker plugin repositories.""" import unittest from random import choice -from urllib.parse import urljoin - -from requests.exceptions import HTTPError from pulp_smash import api, config from pulp_smash.pulp3.constants import REPO_PATH from pulp_smash.pulp3.utils import ( - gen_publisher, gen_repo, get_content, get_versions, - publish, sync, ) @@ -21,7 +16,7 @@ from pulp_docker.tests.functional.constants import ( DOCKER_CONTENT_NAME, DOCKER_REMOTE_PATH, - DOCKER_PUBLISHER_PATH, + DOCKER_PUBLICATION_PATH, ) from pulp_docker.tests.functional.utils import set_up_module as setUpModule # noqa:F401 @@ -51,8 +46,6 @@ def test_all(self): 4. Create a publication by supplying the non-latest ``repository_version``. 5. Assert that the publication ``repository_version`` attribute points to the supplied repository version. - 6. Assert that an exception is raised when providing two different - repository versions to be published at same time. """ body = gen_docker_remote() remote = self.client.post(DOCKER_REMOTE_PATH, body) @@ -63,9 +56,6 @@ def test_all(self): sync(self.cfg, remote, repo) - publisher = self.client.post(DOCKER_PUBLISHER_PATH, gen_publisher()) - self.addCleanup(self.client.delete, publisher['_href']) - # Step 1 repo = self.client.get(repo['_href']) for docker_content in get_content(repo)[DOCKER_CONTENT_NAME]: @@ -77,21 +67,14 @@ def test_all(self): non_latest = choice(version_hrefs[:-1]) # Step 2 - publication = publish(self.cfg, publisher, repo) - + publication1 = self.client.using_handler(api.task_handler).post( + DOCKER_PUBLICATION_PATH, {"repository": repo["_href"]}) # Step 3 - self.assertEqual(publication['repository_version'], version_hrefs[-1]) + self.assertEqual(publication1['repository_version'], version_hrefs[-1]) # Step 4 - publication = publish(self.cfg, publisher, repo, non_latest) + publication2 = self.client.using_handler(api.task_handler).post( + DOCKER_PUBLICATION_PATH, {"repository_version": non_latest}) # Step 5 - self.assertEqual(publication['repository_version'], non_latest) - - # Step 6 - with self.assertRaises(HTTPError): - body = { - 'repository': repo['_href'], - 'repository_version': non_latest - } - self.client.post(urljoin(publisher['_href'], 'publish/'), body) + self.assertEqual(publication2['repository_version'], non_latest) diff --git a/pulp_docker/tests/functional/api/test_pull_content.py b/pulp_docker/tests/functional/api/test_pull_content.py index 0c435fa6..0b7f3746 100644 --- a/pulp_docker/tests/functional/api/test_pull_content.py +++ b/pulp_docker/tests/functional/api/test_pull_content.py @@ -9,9 +9,7 @@ from pulp_smash.pulp3.utils import ( get_content, gen_distribution, - gen_publisher, gen_repo, - publish, sync, ) @@ -24,7 +22,7 @@ DOCKER_CONTENT_NAME, DOCKER_DISTRIBUTION_PATH, DOCKER_REMOTE_PATH, - DOCKER_PUBLISHER_PATH, + DOCKER_PUBLICATION_PATH, DOCKER_UPSTREAM_NAME, DOCKER_UPSTREAM_TAG, ) @@ -41,9 +39,8 @@ def setUpClass(cls): 1. Create a repository. 2. Create a remote pointing to external registry. 3. Sync the repository using the remote and re-read the repo data. - 4. Create a docker publisher. - 5. Use the publisher to create a publication. - 6. Create a docker distribution to serve the publication. + 4. Create a publication. + 5. Create a docker distribution to serve the publication. This tests targets the following issue: @@ -74,26 +71,15 @@ def setUpClass(cls): cls.repo = cls.client.get(_repo['_href']) # Step 4 - cls.publisher = cls.client.post( - DOCKER_PUBLISHER_PATH, gen_publisher() - ) - cls.teardown_cleanups.append( - (cls.client.delete, cls.publisher['_href']) - ) + cls.publication = cls.client.using_handler(api.task_handler).post( + DOCKER_PUBLICATION_PATH, {"repository": _repo['_href']}) # Step 5. - cls.publication = publish(cls.cfg, cls.publisher, cls.repo) - cls.teardown_cleanups.append( - (cls.client.delete, cls.publication['_href']) - ) - - # Step 6. - response_dict = cls.client.post( + response_dict = cls.client.using_handler(api.task_handler).post( DOCKER_DISTRIBUTION_PATH, gen_distribution(publication=cls.publication['_href']) ) - dist_task = cls.client.get(response_dict['task']) - distribution_href = dist_task['created_resources'][0] + distribution_href = response_dict['_href'] cls.distribution = cls.client.get(distribution_href) cls.teardown_cleanups.append( (cls.client.delete, cls.distribution['_href']) diff --git a/pulp_docker/tests/functional/constants.py b/pulp_docker/tests/functional/constants.py index c0c526d4..f99d5c98 100644 --- a/pulp_docker/tests/functional/constants.py +++ b/pulp_docker/tests/functional/constants.py @@ -4,7 +4,6 @@ from pulp_smash.constants import PULP_FIXTURES_BASE_URL from pulp_smash.pulp3.constants import ( BASE_PATH, - BASE_PUBLISHER_PATH, BASE_REMOTE_PATH, CONTENT_PATH ) @@ -15,11 +14,10 @@ DOCKER_CONTENT_NAME = 'docker.manifest-blob' DOCKER_DISTRIBUTION_PATH = urljoin(BASE_PATH, 'docker-distributions/') +DOCKER_PUBLICATION_PATH = urljoin(BASE_PATH, 'docker/publications/') DOCKER_REMOTE_PATH = urljoin(BASE_REMOTE_PATH, 'docker/docker/') -DOCKER_PUBLISHER_PATH = urljoin(BASE_PUBLISHER_PATH, 'docker/docker/') - DOCKER_IMAGE_URL = urljoin(PULP_FIXTURES_BASE_URL, 'docker/busybox:latest.tar') """The URL to a Docker image as created by ``docker save``."""