use kwargs for parse_repository_name

This commit is contained in:
Jimmy Zelinskie 2016-03-09 16:20:28 -05:00
parent 3b52a255b2
commit bb46cc933d
15 changed files with 285 additions and 270 deletions

View file

@ -1,18 +1,22 @@
import logging
import jwt.utils
import json
import features
import hashlib
from peewee import IntegrityError
from flask import make_response, request, url_for
from collections import namedtuple, OrderedDict
from jwkest.jws import SIGNER_ALGS, keyrep
from datetime import datetime
from functools import wraps
import jwt.utils
from peewee import IntegrityError
from flask import make_response, request, url_for
from jwkest.jws import SIGNER_ALGS, keyrep
import features
from app import docker_v2_signing_key, app
from auth.registry_jwt_auth import process_registry_jwt_auth
from endpoints.common import parse_repository_name
from endpoints.decorators import anon_protect
from endpoints.v2 import v2_bp, require_repo_read, require_repo_write
from endpoints.v2.errors import (BlobUnknown, ManifestInvalid, ManifestUnknown, TagInvalid,
@ -22,7 +26,6 @@ from endpoints.notificationhelper import spawn_notification
from digest import digest_tools
from data import model
from data.database import RepositoryTag
from endpoints.common import parse_repository_name
logger = logging.getLogger(__name__)
@ -84,7 +87,8 @@ class SignedManifest(object):
def _validate(self):
for signature in self._signatures:
bytes_to_verify = '{0}.{1}'.format(signature['protected'], jwt.utils.base64url_encode(self.payload))
bytes_to_verify = '{0}.{1}'.format(signature['protected'],
jwt.utils.base64url_encode(self.payload))
signer = SIGNER_ALGS[signature['header']['alg']]
key = keyrep(signature['header']['jwk'])
gk = key.get_key()
@ -163,9 +167,9 @@ class SignedManifest(object):
class SignedManifestBuilder(object):
""" Class which represents a manifest which is currently being built.
"""
def __init__(self, namespace, repo_name, tag, architecture='amd64', schema_ver=1):
repo_name_key = '{0}/{1}'.format(namespace, repo_name)
if namespace == '':
def __init__(self, namespace_name, repo_name, tag, architecture='amd64', schema_ver=1):
repo_name_key = '{0}/{1}'.format(namespace_name, repo_name)
if namespace_name == '':
repo_name_key = repo_name
self._base_payload = {
@ -238,26 +242,26 @@ class SignedManifestBuilder(object):
@v2_bp.route(MANIFEST_TAGNAME_ROUTE, methods=['GET'])
@process_registry_jwt_auth
@parse_repository_name
@parse_repository_name()
@require_repo_read
@anon_protect
def fetch_manifest_by_tagname(namespace, repo_name, manifest_ref):
def fetch_manifest_by_tagname(namespace_name, repo_name, manifest_ref):
try:
manifest = model.tag.load_tag_manifest(namespace, repo_name, manifest_ref)
manifest = model.tag.load_tag_manifest(namespace_name, repo_name, manifest_ref)
except model.InvalidManifestException:
try:
model.tag.get_active_tag(namespace, repo_name, manifest_ref)
model.tag.get_active_tag(namespace_name, repo_name, manifest_ref)
except RepositoryTag.DoesNotExist:
raise ManifestUnknown()
raise ManifestUnknown()
try:
manifest = _generate_and_store_manifest(namespace, repo_name, manifest_ref)
manifest = _generate_and_store_manifest(namespace_name, repo_name, manifest_ref)
except model.DataModelException:
logger.exception('Exception when generating manifest for %s/%s:%s', namespace, repo_name,
logger.exception('Exception when generating manifest for %s/%s:%s', namespace_name, repo_name,
manifest_ref)
raise ManifestUnknown()
repo = model.repository.get_repository(namespace, repo_name)
repo = model.repository.get_repository(namespace_name, repo_name)
if repo is not None:
track_and_log('pull_repo', repo, analytics_name='pull_repo_100x', analytics_sample=0.01)
@ -269,17 +273,17 @@ def fetch_manifest_by_tagname(namespace, repo_name, manifest_ref):
@v2_bp.route(MANIFEST_DIGEST_ROUTE, methods=['GET'])
@process_registry_jwt_auth
@parse_repository_name
@parse_repository_name()
@require_repo_read
@anon_protect
def fetch_manifest_by_digest(namespace, repo_name, manifest_ref):
def fetch_manifest_by_digest(namespace_name, repo_name, manifest_ref):
try:
manifest = model.tag.load_manifest_by_digest(namespace, repo_name, manifest_ref)
manifest = model.tag.load_manifest_by_digest(namespace_name, repo_name, manifest_ref)
except model.InvalidManifestException:
# Without a tag name to reference, we can't make an attempt to generate the manifest
raise ManifestUnknown()
repo = model.repository.get_repository(namespace, repo_name)
repo = model.repository.get_repository(namespace_name, repo_name)
if repo is not None:
track_and_log('pull_repo', repo)
@ -301,11 +305,11 @@ def _reject_manifest2_schema2(func):
@v2_bp.route(MANIFEST_TAGNAME_ROUTE, methods=['PUT'])
@process_registry_jwt_auth
@parse_repository_name
@parse_repository_name()
@require_repo_write
@anon_protect
@_reject_manifest2_schema2
def write_manifest_by_tagname(namespace, repo_name, manifest_ref):
def write_manifest_by_tagname(namespace_name, repo_name, manifest_ref):
try:
manifest = SignedManifest(request.data)
except ValueError:
@ -314,16 +318,16 @@ def write_manifest_by_tagname(namespace, repo_name, manifest_ref):
if manifest.tag != manifest_ref:
raise TagInvalid()
return _write_manifest(namespace, repo_name, manifest)
return _write_manifest(namespace_name, repo_name, manifest)
@v2_bp.route(MANIFEST_DIGEST_ROUTE, methods=['PUT'])
@process_registry_jwt_auth
@parse_repository_name
@parse_repository_name()
@require_repo_write
@anon_protect
@_reject_manifest2_schema2
def write_manifest_by_digest(namespace, repo_name, manifest_ref):
def write_manifest_by_digest(namespace_name, repo_name, manifest_ref):
try:
manifest = SignedManifest(request.data)
except ValueError:
@ -332,7 +336,7 @@ def write_manifest_by_digest(namespace, repo_name, manifest_ref):
if manifest.digest != manifest_ref:
raise ManifestInvalid(detail={'message': 'manifest digest mismatch'})
return _write_manifest(namespace, repo_name, manifest)
return _write_manifest(namespace_name, repo_name, manifest)
def _updated_v1_metadata(v1_metadata_json, updated_id_map):
@ -350,21 +354,21 @@ def _updated_v1_metadata(v1_metadata_json, updated_id_map):
return json.dumps(parsed)
def _write_manifest(namespace, repo_name, manifest):
def _write_manifest(namespace_name, repo_name, manifest):
# Ensure that the manifest is for this repository. If the manifest's namespace is empty, then
# it is for the library namespace and we need an extra check.
if (manifest.namespace == '' and features.LIBRARY_SUPPORT and
namespace == app.config['LIBRARY_NAMESPACE']):
namespace_name == app.config['LIBRARY_NAMESPACE']):
# This is a library manifest. All good.
pass
elif manifest.namespace != namespace:
elif manifest.namespace != namespace_name:
raise NameInvalid()
if manifest.repo_name != repo_name:
raise NameInvalid()
# Ensure that the repository exists.
repo = model.repository.get_repository(namespace, repo_name)
repo = model.repository.get_repository(namespace_name, repo_name)
if repo is None:
raise NameInvalid()
@ -411,8 +415,8 @@ def _write_manifest(namespace, repo_name, manifest):
v1_metadata_str = mdata.v1_metadata_str.encode('utf-8')
working_docker_id = hashlib.sha256(v1_metadata_str + '@' + digest_str).hexdigest()
logger.debug('Rewriting docker_id %s/%s %s -> %s', namespace, repo_name, v1_mdata.docker_id,
working_docker_id)
logger.debug('Rewriting docker_id %s/%s %s -> %s', namespace_name, repo_name,
v1_mdata.docker_id, working_docker_id)
has_rewritten_ids = True
# Store the new docker id in the map
@ -447,7 +451,7 @@ def _write_manifest(namespace, repo_name, manifest):
# Store the manifest pointing to the tag.
manifest_digest = manifest.digest
leaf_layer_id = images_map[layers[-1].v1_metadata.docker_id].docker_image_id
model.tag.store_tag_manifest(namespace, repo_name, tag_name, leaf_layer_id, manifest_digest,
model.tag.store_tag_manifest(namespace_name, repo_name, tag_name, leaf_layer_id, manifest_digest,
manifest.bytes)
# Spawn the repo_push event.
@ -461,29 +465,29 @@ def _write_manifest(namespace, repo_name, manifest):
response = make_response('OK', 202)
response.headers['Docker-Content-Digest'] = manifest_digest
response.headers['Location'] = url_for('v2.fetch_manifest_by_digest',
repository='%s/%s' % (namespace, repo_name),
repository='%s/%s' % (namespace_name, repo_name),
manifest_ref=manifest_digest)
return response
@v2_bp.route(MANIFEST_DIGEST_ROUTE, methods=['DELETE'])
@process_registry_jwt_auth
@parse_repository_name
@parse_repository_name()
@require_repo_write
@anon_protect
def delete_manifest_by_digest(namespace, repo_name, manifest_ref):
def delete_manifest_by_digest(namespace_name, repo_name, manifest_ref):
""" Delete the manifest specified by the digest. Note: there is no equivalent
method for deleting by tag name because it is forbidden by the spec.
"""
try:
manifest = model.tag.load_manifest_by_digest(namespace, repo_name, manifest_ref)
manifest = model.tag.load_manifest_by_digest(namespace_name, repo_name, manifest_ref)
except model.InvalidManifestException:
# Without a tag name to reference, we can't make an attempt to generate the manifest
raise ManifestUnknown()
# Mark the tag as no longer alive.
try:
model.tag.delete_tag(namespace, repo_name, manifest.tag.name)
model.tag.delete_tag(namespace_name, repo_name, manifest.tag.name)
except model.DataModelException:
# Tag is not alive.
raise ManifestUnknown()
@ -494,15 +498,15 @@ def delete_manifest_by_digest(namespace, repo_name, manifest_ref):
return make_response('', 202)
def _generate_and_store_manifest(namespace, repo_name, tag_name):
def _generate_and_store_manifest(namespace_name, repo_name, tag_name):
# First look up the tag object and its ancestors
image = model.tag.get_tag_image(namespace, repo_name, tag_name)
parents = model.image.get_parent_images(namespace, repo_name, image)
image = model.tag.get_tag_image(namespace_name, repo_name, tag_name)
parents = model.image.get_parent_images(namespace_name, repo_name, image)
# If the manifest is being generated under the library namespace, then we make its namespace
# empty.
manifest_namespace = namespace
if features.LIBRARY_SUPPORT and namespace == app.config['LIBRARY_NAMESPACE']:
manifest_namespace = namespace_name
if features.LIBRARY_SUPPORT and namespace_name == app.config['LIBRARY_NAMESPACE']:
manifest_namespace = ''
# Create and populate the manifest builder
@ -520,13 +524,12 @@ def _generate_and_store_manifest(namespace, repo_name, tag_name):
# Write the manifest to the DB. If an existing manifest already exists, return the
# one found.
try:
return model.tag.associate_generated_tag_manifest(namespace, repo_name, tag_name,
return model.tag.associate_generated_tag_manifest(namespace_name, repo_name, tag_name,
manifest.digest, manifest.bytes)
except IntegrityError as ie:
logger.debug('Got integrity error: %s', ie)
try:
return model.tag.load_tag_manifest(namespace, repo_name, tag_name)
return model.tag.load_tag_manifest(namespace_name, repo_name, tag_name)
except model.InvalidManifestException:
logger.exception('Exception when generating manifest')
raise model.DataModelException('Could not load or generate manifest')