This repository has been archived by the owner on Dec 7, 2022. It is now read-only.
/
serializers.py
206 lines (169 loc) · 6.89 KB
/
serializers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
from gettext import gettext as _
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.
Add any new fields if defined on DockerRemote.
Similar to the example above, in DockerContentSerializer.
Additional validators can be added to the parent validators list
For example::
class Meta:
validators = platform.RemoteSerializer.Meta.validators + [myValidator1, myValidator2]
"""
upstream_name = serializers.CharField(
required=True,
allow_blank=False,
help_text=_("Name of the upstream repository")
)
class Meta:
fields = platform.RemoteSerializer.Meta.fields + ('upstream_name',)
model = models.DockerRemote
class DockerPublisherSerializer(platform.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 = 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