def push( self, session, namespace, repo_name, tag_names, images, credentials=None, expected_failure=None, options=None, ): auth = self._auth_for_credentials(credentials) tag_names = [tag_names] if isinstance(tag_names, str) else tag_names # Ping! self.ping(session) # PUT /v1/repositories/{namespace}/{repository}/ result = self.conduct( session, "PUT", "/v1/repositories/%s/" % self.repo_name(namespace, repo_name), expected_status=(201, expected_failure, V1ProtocolSteps.PUT_IMAGES), json_data={}, auth=auth, ) if result.status_code != 201: return headers = {} headers[ "Authorization"] = "token " + result.headers["www-authenticate"] for image in images: assert image.urls is None # PUT /v1/images/{imageID}/json image_json_data = {"id": image.id} if image.size is not None: image_json_data["Size"] = image.size if image.parent_id is not None: image_json_data["parent"] = image.parent_id if image.config is not None: image_json_data["config"] = image.config if image.created is not None: image_json_data["created"] = image.created image_json = json.dumps(image_json_data) response = self.conduct( session, "PUT", "/v1/images/%s/json" % image.id, data=image_json, headers=headers, expected_status=(200, expected_failure, V1ProtocolSteps.PUT_IMAGE_JSON), ) if response.status_code != 200: return # PUT /v1/images/{imageID}/checksum (old style) old_checksum = compute_tarsum(BytesIO(image.bytes), image_json) checksum_headers = {"X-Docker-Checksum": old_checksum} checksum_headers.update(headers) self.conduct(session, "PUT", "/v1/images/%s/checksum" % image.id, headers=checksum_headers) # PUT /v1/images/{imageID}/layer self.conduct( session, "PUT", "/v1/images/%s/layer" % image.id, data=BytesIO(image.bytes), headers=headers, ) # PUT /v1/images/{imageID}/checksum (new style) checksum = compute_simple(BytesIO(image.bytes), image_json) checksum_headers = {"X-Docker-Checksum-Payload": checksum} checksum_headers.update(headers) self.conduct(session, "PUT", "/v1/images/%s/checksum" % image.id, headers=checksum_headers) # PUT /v1/repositories/{namespace}/{repository}/tags/latest for tag_name in tag_names: self.conduct( session, "PUT", "/v1/repositories/%s/tags/%s" % (self.repo_name(namespace, repo_name), tag_name), data='"%s"' % images[-1].id, headers=headers, expected_status=(200, expected_failure, V1ProtocolSteps.PUT_TAG), ) # PUT /v1/repositories/{namespace}/{repository}/images self.conduct( session, "PUT", "/v1/repositories/%s/images" % self.repo_name(namespace, repo_name), expected_status=204, headers=headers, ) return PushResult(manifests=None, headers=headers)
def push( self, session, namespace, repo_name, tag_names, images, credentials=None, expected_failure=None, options=None, ): options = options or ProtocolOptions() scopes = options.scopes or [ "repository:%s:push,pull" % self.repo_name(namespace, repo_name) ] tag_names = [tag_names] if isinstance(tag_names, str) else tag_names # Ping! self.ping(session) # Perform auth and retrieve a token. token, _ = self.auth( session, credentials, namespace, repo_name, scopes=scopes, expected_failure=expected_failure, ) if token is None: assert V2Protocol.FAILURE_CODES[V2ProtocolSteps.AUTH].get(expected_failure) return headers = { "Authorization": "Bearer " + token, "Accept": ",".join(options.accept_mimetypes) if options.accept_mimetypes is not None else "*/*", } # Build fake manifests. manifests = {} blobs = {} for tag_name in tag_names: if self.schema == "oci": manifests[tag_name] = self.build_oci(images, blobs, options) elif self.schema == "schema2": manifests[tag_name] = self.build_schema2(images, blobs, options) elif self.schema == "schema1": manifests[tag_name] = self.build_schema1( namespace, repo_name, tag_name, images, blobs, options ) else: raise NotImplementedError(self.schema) # Push the blob data. if not self._push_blobs( blobs, session, namespace, repo_name, headers, options, expected_failure ): return # Write a manifest for each tag. for tag_name in tag_names: manifest = manifests[tag_name] # Write the manifest. If we expect it to be invalid, we expect a 404 code. Otherwise, we # expect a 201 response for success. put_code = 404 if options.manifest_invalid_blob_references else 201 manifest_headers = {"Content-Type": manifest.media_type} manifest_headers.update(headers) if options.manifest_content_type is not None: manifest_headers["Content-Type"] = options.manifest_content_type tag_or_digest = tag_name if not options.push_by_manifest_digest else manifest.digest self.conduct( session, "PUT", "/v2/%s/manifests/%s" % (self.repo_name(namespace, repo_name), tag_or_digest), data=manifest.bytes.as_encoded_str(), expected_status=(put_code, expected_failure, V2ProtocolSteps.PUT_MANIFEST), headers=manifest_headers, ) return PushResult(manifests=manifests, headers=headers)
def push(self, session, namespace, repo_name, tag_names, images, credentials=None, expected_failure=None, options=None): auth = self._auth_for_credentials(credentials) tag_names = [tag_names] if isinstance(tag_names, str) else tag_names # Ping! self.ping(session) # PUT /v1/repositories/{namespace}/{repository}/ result = self.conduct(session, 'PUT', '/v1/repositories/%s/' % self.repo_name(namespace, repo_name), expected_status=(201, expected_failure, V1ProtocolSteps.PUT_IMAGES), json_data={}, auth=auth) if result.status_code != 201: return headers = {} headers[ 'Authorization'] = 'token ' + result.headers['www-authenticate'] for image in images: assert image.urls is None # PUT /v1/images/{imageID}/json image_json_data = {'id': image.id} if image.size is not None: image_json_data['Size'] = image.size if image.parent_id is not None: image_json_data['parent'] = image.parent_id if image.config is not None: image_json_data['config'] = image.config if image.created is not None: image_json_data['created'] = image.created image_json = json.dumps(image_json_data) response = self.conduct( session, 'PUT', '/v1/images/%s/json' % image.id, data=image_json, headers=headers, expected_status=(200, expected_failure, V1ProtocolSteps.PUT_IMAGE_JSON)) if response.status_code != 200: return # PUT /v1/images/{imageID}/checksum (old style) old_checksum = compute_tarsum(StringIO(image.bytes), image_json) checksum_headers = {'X-Docker-Checksum': old_checksum} checksum_headers.update(headers) self.conduct(session, 'PUT', '/v1/images/%s/checksum' % image.id, headers=checksum_headers) # PUT /v1/images/{imageID}/layer self.conduct(session, 'PUT', '/v1/images/%s/layer' % image.id, data=StringIO(image.bytes), headers=headers) # PUT /v1/images/{imageID}/checksum (new style) checksum = compute_simple(StringIO(image.bytes), image_json) checksum_headers = {'X-Docker-Checksum-Payload': checksum} checksum_headers.update(headers) self.conduct(session, 'PUT', '/v1/images/%s/checksum' % image.id, headers=checksum_headers) # PUT /v1/repositories/{namespace}/{repository}/tags/latest for tag_name in tag_names: self.conduct(session, 'PUT', '/v1/repositories/%s/tags/%s' % (self.repo_name(namespace, repo_name), tag_name), data='"%s"' % images[-1].id, headers=headers, expected_status=(200, expected_failure, V1ProtocolSteps.PUT_TAG)) # PUT /v1/repositories/{namespace}/{repository}/images self.conduct(session, 'PUT', '/v1/repositories/%s/images' % self.repo_name(namespace, repo_name), expected_status=204, headers=headers) return PushResult(manifests=None, headers=headers)
def push_list( self, session, namespace, repo_name, tag_names, manifestlist, manifests, blobs, credentials=None, expected_failure=None, options=None, ): options = options or ProtocolOptions() scopes = options.scopes or [ "repository:%s:push,pull" % self.repo_name(namespace, repo_name) ] tag_names = [tag_names] if isinstance(tag_names, str) else tag_names # Ping! self.ping(session) # Perform auth and retrieve a token. token, _ = self.auth( session, credentials, namespace, repo_name, scopes=scopes, expected_failure=expected_failure, ) if token is None: assert V2Protocol.FAILURE_CODES[V2ProtocolSteps.AUTH].get(expected_failure) return headers = { "Authorization": "Bearer " + token, "Accept": ",".join(options.accept_mimetypes) if options.accept_mimetypes is not None else "*/*", } # Push all blobs. if not self._push_blobs( blobs, session, namespace, repo_name, headers, options, expected_failure ): return # Push the individual manifests. for manifest in manifests: manifest_headers = {"Content-Type": manifest.media_type} manifest_headers.update(headers) self.conduct( session, "PUT", "/v2/%s/manifests/%s" % (self.repo_name(namespace, repo_name), manifest.digest), data=manifest.bytes.as_encoded_str(), expected_status=(201, expected_failure, V2ProtocolSteps.PUT_MANIFEST), headers=manifest_headers, ) # Push the manifest list. for tag_name in tag_names: manifest_headers = {"Content-Type": manifestlist.media_type} manifest_headers.update(headers) if options.manifest_content_type is not None: manifest_headers["Content-Type"] = options.manifest_content_type self.conduct( session, "PUT", "/v2/%s/manifests/%s" % (self.repo_name(namespace, repo_name), tag_name), data=manifestlist.bytes.as_encoded_str(), expected_status=(201, expected_failure, V2ProtocolSteps.PUT_MANIFEST_LIST), headers=manifest_headers, ) return PushResult(manifests=None, headers=headers)