Skip to content
This repository has been archived by the owner on Dec 7, 2022. It is now read-only.

Commit

Permalink
Merge pull request #271 from dkliban/3994-3995-registry
Browse files Browse the repository at this point in the history
Problem: docker client can't pull from pulp_docker
  • Loading branch information
dkliban committed Dec 3, 2018
2 parents 08bb983 + fb8898a commit e65df9c
Show file tree
Hide file tree
Showing 6 changed files with 401 additions and 71 deletions.
80 changes: 21 additions & 59 deletions README.rst
Expand Up @@ -92,7 +92,7 @@ Create a repository ``foo``
.. code:: json
{
"_href": "http://localhost:8000/pulp/api/v3/repositories/1/",
"_href": "/pulp/api/v3/repositories/1/",
...
}
Expand All @@ -106,7 +106,7 @@ Create a new remote ``bar``
.. code:: json
{
"_href": "http://localhost:8000/pulp/pulp/api/v3/remotes/docker/1/",
"_href": "/pulp/pulp/api/v3/remotes/docker/1/",
...
}
Expand All @@ -126,56 +126,17 @@ Look at the new Repository Version created
.. code:: json
{
"_added_href": "http://localhost:8000/pulp/api/v3/repositories/1/versions/1/added_content/",
"_content_href": "http://localhost:8000/pulp/api/v3/repositories/1/versions/1/content/",
"_href": "http://localhost:8000/pulp/api/v3/repositories/1/versions/1/",
"_removed_href": "http://localhost:8000/pulp/api/v3/repositories/1/versions/1/removed_content/",
"_added_href": "/pulp/api/v3/repositories/1/versions/1/added_content/",
"_content_href": "/pulp/api/v3/repositories/1/versions/1/content/",
"_href": "/pulp/api/v3/repositories/1/versions/1/",
"_removed_href": "/pulp/api/v3/repositories/1/versions/1/removed_content/",
"content_summary": {
"docker": 3
},
"created": "2018-02-23T20:29:54.499055Z",
"number": 1
}
Upload ``$CONTENT_NAME`` to Pulp
-----------------------------

Create an Artifact by uploading the docker to Pulp.

``$ http --form POST http://localhost:8000/pulp/api/v3/artifacts/ file@./$CONTENT_NAME``

.. code:: json
{
"_href": "http://localhost:8000/pulp/api/v3/artifacts/1/",
...
}
Create ``docker`` content from an Artifact
-----------------------------------------

Create a content unit and point it to your artifact

``$ http POST http://localhost:8000/pulp/api/v3/content/docker/dockers/ relative_path=$CONTENT_NAME artifact="http://localhost:8000/pulp/api/v3/artifacts/1/"``

.. code:: json
{
"artifact": "http://localhost:8000/pulp/api/v3/artifacts/1/",
"relative_path": "$CONTENT_NAME",
"type": "docker"
}
``$ export CONTENT_HREF=$(http :8000/pulp/api/v3/content/docker/dockers/ | jq -r '.results[] | select(.relative_path == "$CONTENT_NAME") | ._href')``


Add content to repository ``foo``
---------------------------------

``$ http POST $REPO_HREF'versions/' add_content_units:="[\"$CONTENT_HREF\"]"``


Create a ``docker`` Publisher ``baz``
----------------------------------------------

Expand All @@ -184,7 +145,7 @@ Create a ``docker`` Publisher ``baz``
.. code:: json
{
"_href": "http://localhost:8000/pulp/pulp/api/v3/publishers/docker/1/",
"_href": "/pulp/pulp/api/v3/publishers/docker/1/",
...
}
Expand All @@ -198,25 +159,23 @@ Use the ``bar`` Publisher to create a Publication

.. code:: json
[
{
"_href": "http://localhost:8000/pulp/api/v3/tasks/fd4cbecd-6c6a-4197-9cbe-4e45b0516309/",
"task_id": "fd4cbecd-6c6a-4197-9cbe-4e45b0516309"
}
]
{
"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')``

Add a Distribution to Publisher ``bar``
---------------------------------------
Add a Docker Distribution to serve your publication
---------------------------------------------------

``$ http POST http://localhost:8000/pulp/api/v3/distributions/ name='baz' base_path='foo' publication=$PUBLICATION_HREF``
``$ http POST http://localhost:8000/pulp/api/v3/docker-distributions/ name='baz' base_path='foo'
publication=$PUBLICATION_HREF``


.. code:: json
{
"_href": "http://localhost:8000/pulp/api/v3/distributions/1/",
"_href": "/pulp/api/v3/docker-distributions/1/",
...
}
Expand All @@ -225,7 +184,10 @@ Check status of a task

``$ http GET http://localhost:8000/pulp/pulp/api/v3/tasks/82e64412-47f8-4dd4-aa55-9de89a6c549b/``

Download ``$CONTENT_NAME`` from Pulp
------------------------------------------------------------------
Perform a docker pull from Pulp
-------------------------------

If SSL has not been setup for your Pulp, configure docker to work with the insecure registry:
https://docs.docker.com/registry/insecure/#deploy-a-plain-http-registry

``$ http GET http://localhost:8000/pulp/content/foo/$CONTENT_NAME``
``$ docker pull localhost:8000/foo``
164 changes: 157 additions & 7 deletions pulp_docker/app/serializers.py
@@ -1,17 +1,34 @@
"""
Check `Plugin Writer's Guide`_ for more details.
.. _Plugin Writer's Guide:
http://docs.pulpproject.org/en/3.0/nightly/plugins/plugin-writer/index.html
"""
from gettext import gettext as _
from rest_framework import serializers # noqa

from django.conf import settings
from django.core import validators
from django.db.models import Q

from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from pulpcore.plugin import serializers as platform
from pulpcore.plugin.models import Publication, Repository

from . import models


class RegistryPathField(serializers.CharField):
"""
Serializer Field for the registry_path field of the DockerDistribution.
"""

def to_representation(self, value):
"""
Converts a base_path into a registry path.
"""
if settings.CONTENT['HOST']:
host = settings.CONTENT['HOST']
else:
host = self.context['request'].get_host()
return ''.join([host, '/', value])


class DockerRemoteSerializer(platform.RemoteSerializer):
"""
A Serializer for DockerRemote.
Expand Down Expand Up @@ -54,3 +71,136 @@ class Meta:
class Meta:
fields = platform.PublisherSerializer.Meta.fields
model = models.DockerPublisher


class DockerDistributionSerializer(platform.ModelSerializer):
"""
A serializer for DockerDistribution.
"""

_href = platform.IdentityField(
view_name='docker-distributions-detail'
)
name = serializers.CharField(
help_text=_('A unique distribution name. Ex, `rawhide` and `stable`.'),
validators=[validators.MaxLengthValidator(
models.DockerDistribution._meta.get_field('name').max_length,
message=_('Distribution name length must be less than {} characters').format(
models.DockerDistribution._meta.get_field('name').max_length
)),
UniqueValidator(queryset=models.DockerDistribution.objects.all())]
)
base_path = serializers.CharField(
help_text=_('The base (relative) path component of the published url. Avoid paths that \
overlap with other distribution base paths (e.g. "foo" and "foo/bar")'),
validators=[validators.MaxLengthValidator(
models.DockerDistribution._meta.get_field('base_path').max_length,
message=_('Distribution base_path length must be less than {} characters').format(
models.DockerDistribution._meta.get_field('base_path').max_length
)),
UniqueValidator(queryset=models.DockerDistribution.objects.all()),
]
)
publisher = platform.DetailRelatedField(
required=False,
help_text=_('Publications created by this publisher and repository are automatically'
'served as defined by this distribution'),
queryset=models.DockerPublisher.objects.all(),
allow_null=True
)
publication = platform.RelatedField(
required=False,
help_text=_('The publication being served as defined by this distribution'),
queryset=Publication.objects.exclude(complete=False),
view_name='publications-detail',
allow_null=True
)
repository = platform.RelatedField(
required=False,
help_text=_('Publications created by this repository and publisher are automatically'
'served as defined by this distribution'),
queryset=Repository.objects.all(),
view_name='repositories-detail',
allow_null=True
)
registry_path = RegistryPathField(
source='base_path', read_only=True,
help_text=_('The Registry hostame:port/name/ to use with docker pull command defined by '
'this distribution.')
)

class Meta:
model = models.DockerDistribution
fields = platform.ModelSerializer.Meta.fields + (
'name',
'base_path',
'publisher',
'publication',
'registry_path',
'repository',
'content_guard',
)

def _validate_path_overlap(self, path):
# look for any base paths nested in path
search = path.split("/")[0]
q = Q(base_path=search)
for subdir in path.split("/")[1:]:
search = "/".join((search, subdir))
q |= Q(base_path=search)

# look for any base paths that nest path
q |= Q(base_path__startswith='{}/'.format(path))
qs = models.DockerDistribution.objects.filter(q)

if self.instance is not None:
qs = qs.exclude(pk=self.instance.pk)

match = qs.first()
if match:
raise serializers.ValidationError(detail=_("Overlaps with existing distribution '"
"{}'").format(match.name))

return path

def validate_base_path(self, path):
"""
Validate that path is valid.
Args:
path (str): the path at which the registry will be served at
"""
self._validate_relative_path(path)
return self._validate_path_overlap(path)

def validate(self, data):
"""
Validates that the data dict has valid DockerDistribution info.
Args:
data (dict): dict representing a DockerDistribution
"""
super().validate(data)

if 'publisher' in data:
publisher = data['publisher']
elif self.instance:
publisher = self.instance.publisher
else:
publisher = None

if 'repository' in data:
repository = data['repository']
elif self.instance:
repository = self.instance.repository
else:
repository = None

if publisher and not repository:
raise serializers.ValidationError({'repository': _("Repository must be set if "
"publisher is set.")})
if repository and not publisher:
raise serializers.ValidationError({'publisher': _("Publisher must be set if "
"repository is set.")})

return data
4 changes: 1 addition & 3 deletions pulp_docker/app/tasks/publishing.py
Expand Up @@ -30,6 +30,4 @@ def publish(publisher_pk, repository_version_pk):
))

with Publication.create(repository_version, publisher, pass_through=True) as publication:
pass

log.info(_('Publication: {publication} created').format(publication.pk))
log.info(_('Publication: {publication} created').format(publication=publication.pk))
14 changes: 12 additions & 2 deletions pulp_docker/app/urls.py
@@ -1,9 +1,19 @@
from django.conf.urls import url

from pulp_docker.app.views import (
VersionView
BlobManifestView,
TagsListView,
TagView,
VersionView,
)

urlpatterns = [
url(r'^v2/$', VersionView.as_view()),
url(r'^v2/$', VersionView.as_view(), name='registry-root'),
url(r'^v2/(?P<path>.+)/tags/list$', TagsListView.as_view()),
url(r'^v2/(?P<path>.+)/manifests/(?P<digest>sha256:[A-Fa-f0-9]+)$',
BlobManifestView.as_view()),
url(r'^v2/(?P<path>.+)/manifests/(?P<tag_name>[A-Za-z0-9\._-]+)$',
TagView.as_view()),
url(r'^v2/(?P<path>.+)/blobs/(?P<digest>sha256:[A-Fa-f0-9]+)$',
BlobManifestView.as_view())
]

0 comments on commit e65df9c

Please sign in to comment.