3
3
from requests .exceptions import HTTPError
4
4
import json
5
5
from docker_registry_client .AuthorizationService import AuthorizationService
6
+ from .manifest import sign as sign_manifest
6
7
7
8
# urllib3 throws some ssl warnings with older versions of python
8
9
# they're probably ok for the registry client to ignore
@@ -136,10 +137,23 @@ def delete_repository(self, namespace, repository):
136
137
namespace = namespace , repository = repository )
137
138
138
139
140
+ class _Manifest (object ):
141
+ def __init__ (self , content , type , digest ):
142
+ self ._content = content
143
+ self ._type = type
144
+ self ._digest = digest
145
+
146
+
147
+ BASE_CONTENT_TYPE = 'application/vnd.docker.distribution.manifest'
148
+
149
+
139
150
class BaseClientV2 (CommonBaseClient ):
140
151
LIST_TAGS = '/v2/{name}/tags/list'
141
152
MANIFEST = '/v2/{name}/manifests/{reference}'
142
153
BLOB = '/v2/{name}/blobs/{digest}'
154
+ schema_1_signed = BASE_CONTENT_TYPE + '.v1+prettyjws'
155
+ schema_1 = BASE_CONTENT_TYPE + '.v1+json'
156
+ schema_2 = BASE_CONTENT_TYPE + '.v2+json'
143
157
144
158
def __init__ (self , * args , ** kwargs ):
145
159
auth_service_url = kwargs .pop ("auth_service_url" , "" )
@@ -169,11 +183,33 @@ def get_repository_tags(self, name):
169
183
return self ._http_call (self .LIST_TAGS , get , name = name )
170
184
171
185
def get_manifest_and_digest (self , name , reference ):
186
+ m = self .get_manifest (name , reference )
187
+ return m ._content , m ._digest
188
+
189
+ def get_manifest (self , name , reference ):
172
190
self .auth .desired_scope = 'repository:%s:*' % name
173
- response = self ._http_response (self .MANIFEST , get ,
174
- name = name , reference = reference )
191
+ response = self ._http_response (
192
+ self .MANIFEST , get , name = name , reference = reference ,
193
+ schema = self .schema_1_signed ,
194
+ )
175
195
self ._cache_manifest_digest (name , reference , response = response )
176
- return (response .json (), self ._manifest_digests [name , reference ])
196
+ return _Manifest (
197
+ content = response .json (),
198
+ type = response .headers .get ('Content-Type' , 'application/json' ),
199
+ digest = self ._manifest_digests [name , reference ],
200
+ )
201
+
202
+ def put_manifest (self , name , reference , manifest ):
203
+ self .auth .desired_scope = 'repository:%s:*' % name
204
+ content = {}
205
+ content .update (manifest ._content )
206
+ content .update ({'name' : name , 'tag' : reference })
207
+
208
+ return self ._http_call (
209
+ self .MANIFEST , put , data = sign_manifest (content ),
210
+ content_type = self .schema_1_signed , schema = self .schema_1_signed ,
211
+ name = name , reference = reference ,
212
+ )
177
213
178
214
def delete_manifest (self , name , digest ):
179
215
self .auth .desired_scope = 'repository:%s:*' % name
@@ -193,16 +229,20 @@ def _cache_manifest_digest(self, name, reference, response=None):
193
229
untrusted_digest = response .headers .get ('Docker-Content-Digest' )
194
230
self ._manifest_digests [(name , reference )] = untrusted_digest
195
231
196
- def _http_response (self , url , method , data = None , ** kwargs ):
232
+ def _http_response (self , url , method , data = None , content_type = None ,
233
+ schema = None , ** kwargs ):
197
234
"""url -> full target url
198
235
method -> method from requests
199
236
data -> request body
200
237
kwargs -> url formatting args
201
238
"""
202
239
240
+ if schema is None :
241
+ schema = self .schema_2
242
+
203
243
header = {
204
- 'content-type' : 'application/json' ,
205
- 'Accept' : 'application/vnd.docker.distribution.manifest.v2+json' ,
244
+ 'content-type' : content_type or 'application/json' ,
245
+ 'Accept' : schema ,
206
246
}
207
247
208
248
# Token specific part. We add the token in the header if necessary
@@ -219,8 +259,9 @@ def _http_response(self, url, method, data=None, **kwargs):
219
259
220
260
header ['Authorization' ] = 'Bearer %s' % self .auth .token
221
261
222
- if data :
262
+ if data and not content_type :
223
263
data = json .dumps (data )
264
+
224
265
path = url .format (** kwargs )
225
266
logger .debug ("%s %s" , method .__name__ .upper (), path )
226
267
response = method (self .host + path ,
0 commit comments