Merge remote-tracking branch 'upstream/v2-phase4' into python-registry-v2
This commit is contained in:
commit
e7a6176594
105 changed files with 4439 additions and 2074 deletions
|
@ -9,7 +9,7 @@ from data import model
|
|||
from app import app, authentication, userevents, storage
|
||||
from auth.auth import process_auth, generate_signed_token
|
||||
from auth.auth_context import get_authenticated_user, get_validated_token, get_validated_oauth_token
|
||||
from util.names import parse_repository_name
|
||||
from util.names import parse_repository_name, REPOSITORY_NAME_REGEX
|
||||
from auth.permissions import (ModifyRepositoryPermission, UserAdminPermission,
|
||||
ReadRepositoryPermission, CreateRepositoryPermission,
|
||||
repository_read_grant, repository_write_grant)
|
||||
|
@ -173,6 +173,10 @@ def update_user(username):
|
|||
@generate_headers(scope=GrantType.WRITE_REPOSITORY, add_grant_for_status=201)
|
||||
@anon_allowed
|
||||
def create_repository(namespace, repository):
|
||||
# Verify that the repository name is valid.
|
||||
if not REPOSITORY_NAME_REGEX.match(repository):
|
||||
abort(400, message='Invalid repository name. Repository names cannot contain slashes.')
|
||||
|
||||
logger.debug('Looking up repository %s/%s', namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
|
||||
|
@ -232,9 +236,6 @@ def update_images(namespace, repository):
|
|||
# Make sure the repo actually exists.
|
||||
abort(404, message='Unknown repository', issue='unknown-repo')
|
||||
|
||||
logger.debug('GCing repository')
|
||||
model.repository.garbage_collect_repository(namespace, repository)
|
||||
|
||||
# Generate a job for each notification that has been added to this repo
|
||||
logger.debug('Adding notifications for repository')
|
||||
|
||||
|
@ -292,16 +293,31 @@ def put_repository_auth(namespace, repository):
|
|||
abort(501, 'Not Implemented', issue='not-implemented')
|
||||
|
||||
|
||||
def conduct_repo_search(username, query, results):
|
||||
""" Finds matching repositories. """
|
||||
def can_read(repo):
|
||||
if repo.is_public:
|
||||
return True
|
||||
|
||||
return ReadRepositoryPermission(repo.namespace_user.username, repo.name).can()
|
||||
|
||||
only_public = username is None
|
||||
matching_repos = model.repository.get_sorted_matching_repositories(query, only_public, can_read,
|
||||
limit=5)
|
||||
|
||||
for repo in matching_repos:
|
||||
results.append({
|
||||
'name': repo.name,
|
||||
'description': repo.description,
|
||||
'is_public': repo.is_public,
|
||||
'href': '/repository/' + repo.namespace_user.username + '/' + repo.name
|
||||
})
|
||||
|
||||
|
||||
@v1_bp.route('/search', methods=['GET'])
|
||||
@process_auth
|
||||
@anon_protect
|
||||
def get_search():
|
||||
def result_view(repo):
|
||||
return {
|
||||
"name": repo.namespace_user.username + '/' + repo.name,
|
||||
"description": repo.description
|
||||
}
|
||||
|
||||
query = request.args.get('q')
|
||||
|
||||
username = None
|
||||
|
@ -309,14 +325,9 @@ def get_search():
|
|||
if user is not None:
|
||||
username = user.username
|
||||
|
||||
results = []
|
||||
if query:
|
||||
matching = model.repository.get_matching_repositories(query, username)
|
||||
else:
|
||||
matching = []
|
||||
|
||||
results = [result_view(repo) for repo in matching
|
||||
if (repo.visibility.name == 'public' or
|
||||
ReadRepositoryPermission(repo.namespace_user.username, repo.name).can())]
|
||||
conduct_repo_search(username, query, results)
|
||||
|
||||
data = {
|
||||
"query": query,
|
||||
|
|
|
@ -193,11 +193,11 @@ def put_image_layer(namespace, repository, image_id):
|
|||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
try:
|
||||
logger.debug('Retrieving image data')
|
||||
json_data = model.image.get_image_json(repo_image)
|
||||
except (IOError, AttributeError):
|
||||
uuid = repo_image.storage.uuid
|
||||
json_data = repo_image.v1_json_metadata
|
||||
except (AttributeError):
|
||||
logger.exception('Exception when retrieving image data')
|
||||
abort(404, 'Image %(image_id)s not found', issue='unknown-image',
|
||||
image_id=image_id)
|
||||
abort(404, 'Image %(image_id)s not found', issue='unknown-image', image_id=image_id)
|
||||
|
||||
uuid = repo_image.storage.uuid
|
||||
layer_path = store.v1_image_layer_path(uuid)
|
||||
|
@ -241,15 +241,15 @@ def put_image_layer(namespace, repository, image_id):
|
|||
logger.exception('Exception when writing image data')
|
||||
abort(520, 'Image %(image_id)s could not be written. Please try again.', image_id=image_id)
|
||||
|
||||
# Save the size of the image.
|
||||
model.image.set_image_size(image_id, namespace, repository, size_info.compressed_size,
|
||||
size_info.uncompressed_size)
|
||||
|
||||
# Append the computed checksum.
|
||||
csums = []
|
||||
csums.append('sha256:{0}'.format(h.hexdigest()))
|
||||
|
||||
try:
|
||||
# Save the size of the image.
|
||||
model.image.set_image_size(image_id, namespace, repository, size_info.compressed_size,
|
||||
size_info.uncompressed_size)
|
||||
|
||||
if requires_tarsum:
|
||||
tmp.seek(0)
|
||||
csums.append(checksums.compute_tarsum(tmp, json_data))
|
||||
|
@ -315,7 +315,7 @@ def put_image_checksum(namespace, repository, image_id):
|
|||
abort(404, 'Image not found: %(image_id)s', issue='unknown-image', image_id=image_id)
|
||||
|
||||
logger.debug('Looking up repo layer data')
|
||||
if not model.image.has_image_json(repo_image):
|
||||
if not repo_image.v1_json_metadata:
|
||||
abort(404, 'Image not found: %(image_id)s', issue='unknown-image', image_id=image_id)
|
||||
|
||||
logger.debug('Marking image path')
|
||||
|
@ -355,21 +355,17 @@ def get_image_json(namespace, repository, image_id, headers):
|
|||
|
||||
logger.debug('Looking up repo image')
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
|
||||
logger.debug('Looking up repo layer data')
|
||||
try:
|
||||
data = model.image.get_image_json(repo_image)
|
||||
except (IOError, AttributeError):
|
||||
if repo_image is None:
|
||||
flask_abort(404)
|
||||
|
||||
logger.debug('Looking up repo layer size')
|
||||
size = repo_image.storage.image_size
|
||||
|
||||
headers['Content-Type'] = 'application/json'
|
||||
if size is not None:
|
||||
# Note: X-Docker-Size is optional and we *can* end up with a NULL image_size,
|
||||
# so handle this case rather than failing.
|
||||
headers['X-Docker-Size'] = str(size)
|
||||
|
||||
response = make_response(data, 200)
|
||||
response = make_response(repo_image.v1_json_metadata, 200)
|
||||
response.headers.extend(headers)
|
||||
return response
|
||||
|
||||
|
@ -472,7 +468,8 @@ def put_image_json(namespace, repository, image_id):
|
|||
abort(400, 'Image %(image_id)s depends on non existing parent image %(parent_id)s',
|
||||
issue='invalid-request', image_id=image_id, parent_id=parent_id)
|
||||
|
||||
if not image_is_uploading(repo_image) and model.image.has_image_json(repo_image):
|
||||
logger.debug('Checking if image already exists')
|
||||
if repo_image.v1_json_metadata and not image_is_uploading(repo_image):
|
||||
exact_abort(409, 'Image already exists')
|
||||
|
||||
set_uploading_flag(repo_image, True)
|
||||
|
|
|
@ -5,7 +5,7 @@ import json
|
|||
from flask import abort, request, jsonify, make_response, session
|
||||
|
||||
from app import app
|
||||
from util.names import parse_repository_name
|
||||
from util.names import TAG_ERROR, TAG_REGEX, parse_repository_name
|
||||
from auth.auth import process_auth
|
||||
from auth.permissions import (ReadRepositoryPermission,
|
||||
ModifyRepositoryPermission)
|
||||
|
@ -60,6 +60,9 @@ def put_tag(namespace, repository, tag):
|
|||
permission = ModifyRepositoryPermission(namespace, repository)
|
||||
|
||||
if permission.can():
|
||||
if not TAG_REGEX.match(tag):
|
||||
abort(400, TAG_ERROR)
|
||||
|
||||
docker_image_id = json.loads(request.data)
|
||||
model.tag.create_or_update_tag(namespace, repository, tag, docker_image_id)
|
||||
|
||||
|
@ -83,8 +86,6 @@ def delete_tag(namespace, repository, tag):
|
|||
|
||||
if permission.can():
|
||||
model.tag.delete_tag(namespace, repository, tag)
|
||||
model.repository.garbage_collect_repository(namespace, repository)
|
||||
|
||||
return make_response('Deleted', 200)
|
||||
|
||||
abort(403)
|
||||
|
|
Reference in a new issue