def check_blob_exists(namespace_name, repo_name, digest): # Find the blob. blob = registry_model.get_cached_repo_blob(model_cache, namespace_name, repo_name, digest) if blob is None: raise BlobUnknown() # Build the response headers. headers = { "Docker-Content-Digest": digest, "Content-Length": blob.compressed_size, "Content-Type": BLOB_CONTENT_TYPE, } # If our storage supports range requests, let the client know. if storage.get_supports_resumable_downloads(blob.placements): headers["Accept-Ranges"] = "bytes" # Write the response to the client. return Response(headers=headers)
def download_blob(namespace_name, repo_name, digest): # Find the blob. blob = registry_model.get_cached_repo_blob(model_cache, namespace_name, repo_name, digest) if blob is None: raise BlobUnknown() # Build the response headers. headers = {"Docker-Content-Digest": digest} # If our storage supports range requests, let the client know. if storage.get_supports_resumable_downloads(blob.placements): headers["Accept-Ranges"] = "bytes" image_pulled_bytes.labels("v2").inc(blob.compressed_size) # Short-circuit by redirecting if the storage supports it. path = blob.storage_path logger.debug("Looking up the direct download URL for path: %s", path) direct_download_url = storage.get_direct_download_url(blob.placements, path, get_request_ip()) if direct_download_url: logger.debug("Returning direct download URL") resp = redirect(direct_download_url) resp.headers.extend(headers) return resp # Close the database connection before we stream the download. logger.debug("Closing database connection before streaming layer data") headers.update( { "Content-Length": blob.compressed_size, "Content-Type": BLOB_CONTENT_TYPE, } ) with database.CloseForLongOperation(app.config): # Stream the response to the client. return Response( storage.stream_read(blob.placements, path), headers=headers, )
def download_blob(namespace_name, repo_name, digest): # Find the blob. blob = registry_model.get_cached_repo_blob(model_cache, namespace_name, repo_name, digest) if blob is None: raise BlobUnknown() # Build the response headers. headers = {'Docker-Content-Digest': digest} # If our storage supports range requests, let the client know. if storage.get_supports_resumable_downloads(blob.placements): headers['Accept-Ranges'] = 'bytes' metric_queue.pull_byte_count.Inc(blob.compressed_size, labelvalues=['v2']) # Short-circuit by redirecting if the storage supports it. path = blob.storage_path logger.debug('Looking up the direct download URL for path: %s', path) direct_download_url = storage.get_direct_download_url( blob.placements, path, get_request_ip()) if direct_download_url: logger.debug('Returning direct download URL') resp = redirect(direct_download_url) resp.headers.extend(headers) return resp # Close the database connection before we stream the download. logger.debug('Closing database connection before streaming layer data') with database.CloseForLongOperation(app.config): # Stream the response to the client. return Response( storage.stream_read(blob.placements, path), headers=headers.update({ 'Content-Length': blob.compressed_size, 'Content-Type': BLOB_CONTENT_TYPE, }), )
def _try_to_mount_blob(repository_ref, mount_blob_digest): """ Attempts to mount a blob requested by the user from another repository. """ logger.debug("Got mount request for blob `%s` into `%s`", mount_blob_digest, repository_ref) from_repo = request.args.get("from", None) if from_repo is None: raise InvalidRequest(message="Missing `from` repository argument") # Ensure the user has access to the repository. logger.debug( "Got mount request for blob `%s` under repository `%s` into `%s`", mount_blob_digest, from_repo, repository_ref, ) from_namespace, from_repo_name = parse_namespace_repository( from_repo, app.config["LIBRARY_NAMESPACE"], include_tag=False ) from_repository_ref = registry_model.lookup_repository(from_namespace, from_repo_name) if from_repository_ref is None: logger.debug("Could not find from repo: `%s/%s`", from_namespace, from_repo_name) return None # First check permission. read_permission = ReadRepositoryPermission(from_namespace, from_repo_name).can() if not read_permission: # If no direct permission, check if the repostory is public. if not from_repository_ref.is_public: logger.debug( "No permission to mount blob `%s` under repository `%s` into `%s`", mount_blob_digest, from_repo, repository_ref, ) return None # Lookup if the mount blob's digest exists in the repository. mount_blob = registry_model.get_cached_repo_blob( model_cache, from_namespace, from_repo_name, mount_blob_digest ) if mount_blob is None: logger.debug("Blob `%s` under repository `%s` not found", mount_blob_digest, from_repo) return None logger.debug( "Mounting blob `%s` under repository `%s` into `%s`", mount_blob_digest, from_repo, repository_ref, ) # Mount the blob into the current repository and return that we've completed the operation. expiration_sec = app.config["PUSH_TEMP_TAG_EXPIRATION_SEC"] mounted = registry_model.mount_blob_into_repository(mount_blob, repository_ref, expiration_sec) if not mounted: logger.debug( "Could not mount blob `%s` under repository `%s` not found", mount_blob_digest, from_repo, ) return # Return the response for the blob indicating that it was mounted, and including its content # digest. logger.debug( "Mounted blob `%s` under repository `%s` into `%s`", mount_blob_digest, from_repo, repository_ref, ) namespace_name = repository_ref.namespace_name repo_name = repository_ref.name return Response( status=201, headers={ "Docker-Content-Digest": mount_blob_digest, "Location": get_app_url() + url_for( "v2.download_blob", repository="%s/%s" % (namespace_name, repo_name), digest=mount_blob_digest, ), }, )