Пример #1
0
def put_image_layer(image_id):
    try:
        json_data = store.get_content(store.image_json_path(image_id))
        checksum = store.get_content(store.image_checksum_path(image_id))
    except IOError:
        return api_error('JSON\'s image not found', 404)
    layer_path = store.image_layer_path(image_id)
    mark_path = store.image_mark_path(image_id)
    if store.exists(layer_path) and not store.exists(mark_path):
        return api_error('Image already exists', 409)
    input_stream = request.stream
    if request.headers.get('transfer-encoding') == 'chunked':
        # Careful, might work only with WSGI servers supporting chunked
        # encoding (Gunicorn)
        input_stream = request.environ['wsgi.input']
    store.stream_write(layer_path, input_stream)
    # FIXME(sam): Compute the checksum while uploading the image to save time
    checksum_parts = checksum.split(':')
    computed_checksum = compute_image_checksum(checksum_parts[0], image_id,
                                               json_data)
    if computed_checksum != checksum_parts[1].lower():
        logger.debug('put_image_layer: Wrong checksum')
        return api_error('Checksum mismatch, ignoring the layer')
    # Checksum is ok, we remove the marker
    store.remove(mark_path)
    return response()
Пример #2
0
def put_image_layer(image_id):
    try:
        json_data = store.get_content(store.image_json_path(image_id))
        checksum = store.get_content(store.image_checksum_path(image_id))
    except IOError:
        return api_error('JSON\'s image not found', 404)
    layer_path = store.image_layer_path(image_id)
    mark_path = store.image_mark_path(image_id)
    if store.exists(layer_path) and not store.exists(mark_path):
        return api_error('Image already exists', 409)
    input_stream = request.stream
    if request.headers.get('transfer-encoding') == 'chunked':
        # Careful, might work only with WSGI servers supporting chunked
        # encoding (Gunicorn)
        input_stream = request.environ['wsgi.input']
    store.stream_write(layer_path, input_stream)
    # FIXME(sam): Compute the checksum while uploading the image to save time
    checksum_parts = checksum.split(':')
    computed_checksum = compute_image_checksum(checksum_parts[0], image_id,
            json_data)
    if computed_checksum != checksum_parts[1].lower():
        logger.debug('put_image_layer: Wrong checksum')
        return api_error('Checksum mismatch, ignoring the layer')
    # Checksum is ok, we remove the marker
    store.remove(mark_path)
    return response()
Пример #3
0
def put_tag(namespace, repository, tag):
    logger.debug("[put_tag] namespace={0}; repository={1}; tag={2}".format(
        namespace, repository, tag))
    data = None
    try:
        data = json.loads(flask.request.data)
    except json.JSONDecodeError:
        pass
    if not data or not isinstance(data, basestring):
        return toolkit.api_error('Invalid data')
    if not store.exists(store.image_json_path(data)):
        return toolkit.api_error('Image not found', 404)
    store.put_content(store.tag_path(namespace, repository, tag), data)
    sender = flask.current_app._get_current_object()
    signals.tag_created.send(sender,
                             namespace=namespace,
                             repository=repository,
                             tag=tag,
                             value=data)
    # Write some meta-data about the repos
    ua = flask.request.headers.get('user-agent', '')
    data = create_tag_json(user_agent=ua)
    json_path = store.repository_tag_json_path(namespace, repository, tag)
    store.put_content(json_path, data)
    if tag == "latest":  # TODO(dustinlacewell) : deprecate this for v2
        json_path = store.repository_json_path(namespace, repository)
        store.put_content(json_path, data)
    return toolkit.response()
Пример #4
0
def put_tag(namespace, repository, tag):
    logger.debug("[put_tag] namespace={0}; repository={1}; tag={2}".format(
                 namespace, repository, tag))
    data = None
    try:
        data = json.loads(flask.request.data)
    except json.JSONDecodeError:
        pass
    if not data or not isinstance(data, basestring):
        return toolkit.api_error('Invalid data')
    if not store.exists(store.image_json_path(data)):
        return toolkit.api_error('Image not found', 404)
    store.put_content(store.tag_path(namespace, repository, tag), data)
    sender = flask.current_app._get_current_object()
    signals.tag_created.send(sender, namespace=namespace,
                             repository=repository, tag=tag, value=data)
    # Write some meta-data about the repos
    ua = flask.request.headers.get('user-agent', '')
    data = create_tag_json(user_agent=ua)
    json_path = store.repository_tag_json_path(namespace, repository, tag)
    store.put_content(json_path, data)
    if tag == "latest":  # TODO(dustinlacewell) : deprecate this for v2
        json_path = store.repository_json_path(namespace, repository)
        store.put_content(json_path, data)
    return toolkit.response()
Пример #5
0
def put_image_layer(image_id):
    try:
        json_data = store.get_content(store.image_json_path(image_id))
    except IOError:
        return api_error('Image not found', 404)
    layer_path = store.image_layer_path(image_id)
    mark_path = store.image_mark_path(image_id)
    if store.exists(layer_path) and not store.exists(mark_path):
        return api_error('Image already exists', 409)
    input_stream = request.stream
    if request.headers.get('transfer-encoding') == 'chunked':
        # Careful, might work only with WSGI servers supporting chunked
        # encoding (Gunicorn)
        input_stream = request.environ['wsgi.input']
    store.stream_write(layer_path, input_stream)
    # FIXME(sam): Compute the checksum while uploading the image to save time
    try:
        checksum = store.get_content(store.image_checksum_path(image_id))
    except IOError:
        # We don't have a checksum stored yet, that's fine skipping the check.
        # Not removing the mark though, image is not downloadable yet.
        return response()
    if check_image_checksum(image_id, checksum, json_data) is False:
        logger.debug('put_image_layer: Wrong checksum')
        return api_error('Checksum mismatch, ignoring the layer')
    # Checksum is ok, we remove the marker
    store.remove(mark_path)
    return response()
Пример #6
0
def get_image_json(image_id, headers):
    try:
        repository = toolkit.get_repository()
        if repository and store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        # If no auth token found, either standalone registry or privileged
        # access. In both cases, access is always "public".
        return _get_image_json(image_id, headers)
    except IOError:
        return toolkit.api_error('Image not found', 404)
Пример #7
0
def get_image_json(image_id, headers):
    try:
        repository = toolkit.get_repository()
        if repository and store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        # If no auth token found, either standalone registry or privileged
        # access. In both cases, access is always "public".
        return _get_image_json(image_id, headers)
    except IOError:
        return toolkit.api_error('Image not found', 404)
Пример #8
0
def put_image_layer(image_id):
    try:
        json_data = store.get_content(store.image_json_path(image_id))
    except IOError:
        return toolkit.api_error('Image not found', 404)
    layer_path = store.image_layer_path(image_id)
    mark_path = store.image_mark_path(image_id)
    if store.exists(layer_path) and not store.exists(mark_path):
        return toolkit.api_error('Image already exists', 409)
    input_stream = flask.request.stream
    if flask.request.headers.get('transfer-encoding') == 'chunked':
        # Careful, might work only with WSGI servers supporting chunked
        # encoding (Gunicorn)
        input_stream = flask.request.environ['wsgi.input']
    # compute checksums
    csums = []
    sr = toolkit.SocketReader(input_stream)
    tmp, store_hndlr = storage.temp_store_handler()
    sr.add_handler(store_hndlr)
    h, sum_hndlr = checksums.simple_checksum_handler(json_data)
    sr.add_handler(sum_hndlr)
    store.stream_write(layer_path, sr)

    # read layer files and cache them
    try:
        files_json = json.dumps(layers.get_image_files_from_fobj(tmp))
        layers.set_image_files_cache(image_id, files_json)
    except Exception as e:
        logger.debug('put_image_layer: Error when caching layer file-tree:'
                     '{0}'.format(e))

    csums.append('sha256:{0}'.format(h.hexdigest()))
    try:
        tmp.seek(0)
        csums.append(checksums.compute_tarsum(tmp, json_data))
    except (IOError, checksums.TarError) as e:
        logger.debug('put_image_layer: Error when computing tarsum '
                     '{0}'.format(e))
    try:
        checksum = store.get_content(store.image_checksum_path(image_id))
    except IOError:
        # We don't have a checksum stored yet, that's fine skipping the check.
        # Not removing the mark though, image is not downloadable yet.
        flask.session['checksum'] = csums
        return toolkit.response()
    # We check if the checksums provided matches one the one we computed
    if checksum not in csums:
        logger.debug('put_image_layer: Wrong checksum')
        return toolkit.api_error('Checksum mismatch, ignoring the layer')

    tmp.close()

    # Checksum is ok, we remove the marker
    store.remove(mark_path)
    return toolkit.response()
Пример #9
0
def get_private_image_json(image_id):
    repository = toolkit.get_repository()
    if not repository:
        # No auth token found, either standalone registry or privileged access
        # In both cases, private images are "disabled"
        return toolkit.api_error('Image not found', 404)
    try:
        if not store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        return _get_image_json(image_id)
    except IOError:
        return toolkit.api_error('Image not found', 404)
Пример #10
0
def put_repository(namespace, repository, images=False):
    data = None
    try:
        data = json.loads(request.data)
    except json.JSONDecodeError:
        return api_error('Error Decoding JSON', 400)
    if not data or not isinstance(data, list):
        return api_error('Invalid data')
    update_index_images(namespace, repository, request.data)
    headers = generate_headers(namespace, repository, 'write')
    code = 204 if images is True else 200
    return response('', code, headers)
Пример #11
0
def put_repository(namespace, repository, images=False):
    data = None
    try:
        data = json.loads(flask.request.data)
    except json.JSONDecodeError:
        return toolkit.api_error('Error Decoding JSON', 400)
    if not isinstance(data, list):
        return toolkit.api_error('Invalid data')
    update_index_images(namespace, repository, flask.request.data)
    headers = generate_headers(namespace, repository, 'write')
    code = 204 if images is True else 200
    return toolkit.response('', code, headers)
Пример #12
0
def put_tag(namespace, repository, tag):
    data = None
    try:
        data = json.loads(request.data)
    except json.JSONDecodeError:
        pass
    if not data or not isinstance(data, basestring):
        return api_error('Invalid data')
    if not store.exists(store.image_json_path(data)):
        return api_error('Image not found', 404)
    store.put_content(store.tag_path(namespace, repository, tag), data)
    return response()
Пример #13
0
def get_private_image_json(image_id):
    repository = toolkit.get_repository()
    if not repository:
        # No auth token found, either standalone registry or privileged access
        # In both cases, private images are "disabled"
        return toolkit.api_error('Image not found', 404)
    try:
        if not store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        return _get_image_json(image_id)
    except IOError:
        return toolkit.api_error('Image not found', 404)
Пример #14
0
def get_image_files(image_id, headers):
    try:
        repository = toolkit.get_repository()
        if repository and store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        # If no auth token found, either standalone registry or privileged
        # access. In both cases, access is always "public".
        data = layers.get_image_files_json(image_id)
        return toolkit.response(data, headers=headers, raw=True)
    except IOError:
        return toolkit.api_error('Image not found', 404)
    except tarfile.TarError:
        return toolkit.api_error('Layer format not supported', 400)
Пример #15
0
def put_tag(namespace, repository, tag):
    logger.debug("[put_tag] namespace={0}; repository={1}; tag={2}".format(namespace, repository, tag))
    data = None
    try:
        data = json.loads(request.data)
    except json.JSONDecodeError:
        pass
    if not data or not isinstance(data, basestring):
        return api_error("Invalid data")
    if not store.exists(store.image_json_path(data)):
        return api_error("Image not found", 404)
    store.put_content(store.tag_path(namespace, repository, tag), data)
    return response()
Пример #16
0
def get_image_files(image_id, headers):
    try:
        repository = toolkit.get_repository()
        if repository and store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        # If no auth token found, either standalone registry or privileged
        # access. In both cases, access is always "public".
        data = layers.get_image_files_json(image_id)
        return toolkit.response(data, headers=headers, raw=True)
    except IOError:
        return toolkit.api_error('Image not found', 404)
    except tarfile.TarError:
        return toolkit.api_error('Layer format not supported', 400)
Пример #17
0
def get_image_layer(image_id, headers):
    try:
        bytes_range = None
        if store.supports_bytes_range:
            headers['Accept-Ranges'] = 'bytes'
            bytes_range = _parse_bytes_range()
        repository = toolkit.get_repository()
        if repository and store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        # If no auth token found, either standalone registry or privileged
        # access. In both cases, access is always "public".
        return _get_image_layer(image_id, headers, bytes_range)
    except IOError:
        return toolkit.api_error('Image not found', 404)
Пример #18
0
def get_image_layer(image_id, headers):
    try:
        bytes_range = None
        if store.supports_bytes_range:
            headers['Accept-Ranges'] = 'bytes'
            bytes_range = _parse_bytes_range()
        repository = toolkit.get_repository()
        if repository and store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        # If no auth token found, either standalone registry or privileged
        # access. In both cases, access is always "public".
        return _get_image_layer(image_id, headers, bytes_range)
    except IOError:
        return toolkit.api_error('Image not found', 404)
Пример #19
0
def get_private_image_files(image_id, headers):
    repository = toolkit.get_repository()
    if not repository:
        # No auth token found, either standalone registry or privileged access
        # In both cases, private images are "disabled"
        return toolkit.api_error('Image not found', 404)
    try:
        if not store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        data = layers.get_image_files_json(image_id)
        return toolkit.response(data, headers=headers, raw=True)
    except IOError:
        return toolkit.api_error('Image not found', 404)
    except tarfile.TarError:
        return toolkit.api_error('Layer format not supported', 400)
Пример #20
0
def get_private_image_files(image_id, headers):
    repository = toolkit.get_repository()
    if not repository:
        # No auth token found, either standalone registry or privileged access
        # In both cases, private images are "disabled"
        return toolkit.api_error('Image not found', 404)
    try:
        if not store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        data = layers.get_image_files_json(image_id)
        return toolkit.response(data, headers=headers, raw=True)
    except IOError:
        return toolkit.api_error('Image not found', 404)
    except tarfile.TarError:
        return toolkit.api_error('Layer format not supported', 400)
Пример #21
0
def get_tag(namespace, repository, tag):
    data = None
    try:
        data = store.get_content(store.tag_path(namespace, repository, tag))
    except IOError:
        return api_error('Tag not found', 404)
    return response(data)
Пример #22
0
def delete_repository(namespace, repository):
    logger.debug("[delete_repository] namespace={0}; repository={1}".format(namespace, repository))
    try:
        store.remove(store.tag_path(namespace, repository))
    except OSError:
        return api_error("Repository not found", 404)
    return response()
Пример #23
0
def _get_image_layer(image_id, headers=None, bytes_range=None):
    if headers is None:
        headers = {}
    try:
        accel_uri_prefix = cfg.nginx_x_accel_redirect
        path = store.image_layer_path(image_id)
        if accel_uri_prefix:
            if isinstance(store, storage.local.LocalStorage):
                accel_uri = '/'.join([accel_uri_prefix, path])
                headers['X-Accel-Redirect'] = accel_uri
                logger.debug('send accelerated {0} ({1})'.format(
                    accel_uri, headers))
                return flask.Response('', headers=headers)
            else:
                logger.warn('nginx_x_accel_redirect config set,'
                            ' but storage is not LocalStorage')
        status = None
        if bytes_range:
            status = 206
            headers['Content-Range'] = '{0}-{1}/*'.format(*bytes_range)
        return flask.Response(store.stream_read(path, bytes_range),
                              headers=headers,
                              status=status)
    except IOError:
        return toolkit.api_error('Image not found', 404)
Пример #24
0
def get_image_ancestry(image_id, headers):
    ancestry_path = store.image_ancestry_path(image_id)
    try:
        data = store.get_content(ancestry_path)
    except IOError:
        return toolkit.api_error('Image not found', 404)
    return toolkit.response(json.loads(data), headers=headers)
Пример #25
0
def delete_tag(namespace, repository, tag):
    logger.debug("[delete_tag] namespace={0}; repository={1}; tag={2}".format(namespace, repository, tag))
    try:
        store.remove(store.tag_path(namespace, repository, tag))
    except OSError:
        return api_error("Tag not found", 404)
    return response()
Пример #26
0
def delete_repository(namespace, repository):
    """Remove a repository from storage

    This endpoint exists in both the registry API [1] and the indexer
    API [2], but has the same semantics in each instance.  It's in the
    tags module (instead of the index module which handles most
    repository tasks) because it should be available regardless of
    whether the rest of the index-module endpoints are enabled via the
    'standalone' config setting.

    [1]: http://docs.docker.io/en/latest/reference/api/registry_api/#delete--v1-repositories-%28namespace%29-%28repository%29- # nopep8
    [2]: http://docs.docker.io/en/latest/reference/api/index_api/#delete--v1-repositories-%28namespace%29-%28repo_name%29- # nopep8
    """
    logger.debug("[delete_repository] namespace={0}; repository={1}".format(
        namespace, repository))
    try:
        for tag_name, tag_content in get_tags(namespace=namespace,
                                              repository=repository):
            delete_tag(namespace=namespace,
                       repository=repository,
                       tag=tag_name)
        # TODO(wking): remove images, but may need refcounting
        store.remove(
            store.repository_path(namespace=namespace, repository=repository))
    except OSError:
        return toolkit.api_error('Repository not found', 404)
    else:
        sender = flask.current_app._get_current_object()
        signals.repository_deleted.send(sender,
                                        namespace=namespace,
                                        repository=repository)
    return toolkit.response()
Пример #27
0
def get_image_ancestry(image_id, headers):
    ancestry_path = store.image_ancestry_path(image_id)
    try:
        data = store.get_content(ancestry_path)
    except IOError:
        return toolkit.api_error('Image not found', 404)
    return toolkit.response(json.loads(data), headers=headers)
Пример #28
0
def delete_repository(namespace, repository):
    """Remove a repository from storage

    This endpoint exists in both the registry API [1] and the indexer
    API [2], but has the same semantics in each instance.  It's in the
    tags module (instead of the index module which handles most
    repository tasks) because it should be available regardless of
    whether the rest of the index-module endpoints are enabled via the
    'standalone' config setting.

    [1]: http://docs.docker.io/en/latest/reference/api/registry_api/#delete--v1-repositories-%28namespace%29-%28repository%29- # nopep8
    [2]: http://docs.docker.io/en/latest/reference/api/index_api/#delete--v1-repositories-%28namespace%29-%28repo_name%29- # nopep8
    """
    logger.debug("[delete_repository] namespace={0}; repository={1}".format(
                 namespace, repository))
    try:
        for tag_name, tag_content in get_tags(
                namespace=namespace, repository=repository):
            delete_tag(
                namespace=namespace, repository=repository, tag=tag_name)
        # TODO(wking): remove images, but may need refcounting
        store.remove(store.repository_path(
            namespace=namespace, repository=repository))
    except OSError:
        return toolkit.api_error('Repository not found', 404)
    else:
        sender = flask.current_app._get_current_object()
        signals.repository_deleted.send(
            sender, namespace=namespace, repository=repository)
    return toolkit.response()
Пример #29
0
def put_tag(namespace, repository, tag):
    logger.debug("[put_tag] namespace={0}; repository={1}; tag={2}".format(
                 namespace, repository, tag))
    data = None
    try:
        data = json.loads(flask.request.data)
    except json.JSONDecodeError:
        pass
    if not data or not isinstance(data, basestring):
        return toolkit.api_error('Invalid data')
    if not store.exists(store.image_json_path(data)):
        return toolkit.api_error('Image not found', 404)
    store.put_content(store.tag_path(namespace, repository, tag), data)
    sender = flask.current_app._get_current_object()
    signals.tag_created.send(sender, namespace=namespace,
                             repository=repository, tag=tag, value=data)
    return toolkit.response()
Пример #30
0
def get_post_users():
    if flask.request.method == 'GET':
        return toolkit.response('OK', 200)
    try:
        json.loads(flask.request.data)
    except json.JSONDecodeError:
        return toolkit.api_error('Error Decoding JSON', 400)
    return toolkit.response('User Created', 201)
Пример #31
0
def get_private_image_layer(image_id):
    try:
        headers = None
        bytes_range = None
        if store.supports_bytes_range:
            headers['Accept-Ranges'] = 'bytes'
            bytes_range = _parse_bytes_range()
        repository = toolkit.get_repository()
        if not repository:
            # No auth token found, either standalone registry or privileged
            # access. In both cases, private images are "disabled"
            return toolkit.api_error('Image not found', 404)
        if not store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        return _get_image_layer(image_id, headers, bytes_range)
    except IOError:
        return toolkit.api_error('Image not found', 404)
Пример #32
0
def get_post_users():
    if request.method == 'GET':
        return response('OK', 200)
    try:
        json.loads(request.data)
    except json.JSONDecodeError:
        return api_error('Error Decoding JSON', 400)
    return response('User Created', 201)
Пример #33
0
def put_tag(namespace, repository, tag):
    logger.debug("[put_tag] namespace={0}; repository={1}; tag={2}".format(
                 namespace, repository, tag))
    data = None
    try:
        data = json.loads(flask.request.data)
    except json.JSONDecodeError:
        pass
    if not data or not isinstance(data, basestring):
        return toolkit.api_error('Invalid data')
    if not store.exists(store.image_json_path(data)):
        return toolkit.api_error('Image not found', 404)
    store.put_content(store.tag_path(namespace, repository, tag), data)
    sender = flask.current_app._get_current_object()
    signals.tag_created.send(sender, namespace=namespace,
                             repository=repository, tag=tag, value=data)
    return toolkit.response()
Пример #34
0
def delete_repository(namespace, repository):
    logger.debug("[delete_repository] namespace={0}; repository={1}".format(
                 namespace, repository))
    try:
        store.remove(store.tag_path(namespace, repository))
    except OSError:
        return api_error('Repository not found', 404)
    return response()
Пример #35
0
def get_post_users():
    if flask.request.method == "GET":
        return toolkit.response("OK", 200)
    try:
        json.loads(flask.request.data)
    except json.JSONDecodeError:
        return toolkit.api_error("Error Decoding JSON", 400)
    return toolkit.response("User Created", 201)
Пример #36
0
def delete_tag(namespace, repository, tag):
    logger.debug("[delete_tag] namespace={0}; repository={1}; tag={2}".format(
                 namespace, repository, tag))
    try:
        store.remove(store.tag_path(namespace, repository, tag))
    except OSError:
        return api_error('Tag not found', 404)
    return response()
Пример #37
0
def get_tag(namespace, repository, tag):
    logger.debug("[get_tag] namespace={0}; repository={1}; tag={2}".format(namespace, repository, tag))
    data = None
    try:
        data = store.get_content(store.tag_path(namespace, repository, tag))
    except IOError:
        return api_error("Tag not found", 404)
    return response(data)
Пример #38
0
def get_private_image_layer(image_id):
    try:
        headers = None
        bytes_range = None
        if store.supports_bytes_range:
            headers['Accept-Ranges'] = 'bytes'
            bytes_range = _parse_bytes_range()
        repository = toolkit.get_repository()
        if not repository:
            # No auth token found, either standalone registry or privileged
            # access. In both cases, private images are "disabled"
            return toolkit.api_error('Image not found', 404)
        if not store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)
        return _get_image_layer(image_id, headers, bytes_range)
    except IOError:
        return toolkit.api_error('Image not found', 404)
Пример #39
0
def put_image_json(image_id):
    try:
        data = json.loads(request.data)
    except json.JSONDecodeError:
        pass
    if not data or not isinstance(data, dict):
        return api_error('Invalid JSON')
    for key in ['id']:
        if key not in data:
            return api_error('Missing key `{0}\' in JSON'.format(key))
    # Read the checksum
    checksum = request.headers.get('x-docker-checksum', '')
    if checksum:
        # Storing the checksum is optional at this stage
        err = store_checksum(image_id, checksum)
        if err:
            return api_error(err)
    if image_id != data['id']:
        return api_error('JSON data contains invalid id')
    if check_images_list(image_id) is False:
        return api_error('This image does not belong to the repository')
    parent_id = data.get('parent')
    if parent_id and not store.exists(store.image_json_path(data['parent'])):
        return api_error('Image depends on a non existing parent')
    json_path = store.image_json_path(image_id)
    mark_path = store.image_mark_path(image_id)
    if store.exists(json_path) and not store.exists(mark_path):
        return api_error('Image already exists', 409)
    # If we reach that point, it means that this is a new image or a retry
    # on a failed push
    store.put_content(mark_path, 'true')
    store.put_content(json_path, request.data)
    generate_ancestry(image_id, parent_id)
    return response()
Пример #40
0
def get_repository_images(namespace, repository):
    data = None
    try:
        path = store.index_images_path(namespace, repository)
        data = store.get_content(path)
    except IOError:
        return api_error('images not found', 404)
    headers = generate_headers(namespace, repository, 'read')
    return response(data, 200, headers, True)
Пример #41
0
def delete_repository(namespace, repository):
    logger.debug("[delete_repository] namespace={0}; repository={1}".format(
                 namespace, repository))
    try:
        store.remove(store.tag_path(namespace, repository))
        #TODO(samalba): Trigger tags_deleted signals
    except OSError:
        return toolkit.api_error('Repository not found', 404)
    return toolkit.response()
Пример #42
0
def _get_tags(namespace, repository):
    logger.debug("[get_tags] namespace={0}; repository={1}".format(
        namespace, repository))
    try:
        data = dict((tag_name, tag_content) for tag_name, tag_content in
                    get_tags(namespace=namespace, repository=repository))
    except OSError:
        return toolkit.api_error('Repository not found', 404)
    return toolkit.response(data)
Пример #43
0
def get_post_users():
    if flask.request.method == 'GET':
        return toolkit.response('OK', 200)
    try:
        data = json.loads(flask.request.data)
        if Auth.signin(data):
            return toolkit.response('OK', 200)
        else:
            cfg = config.load()
            if not cfg.allow_signup:
                return toolkit.api_error('Signup is not allowed', 400)
            else:
                if Auth.signup(data):
                    return toolkit.response('User Created', 201)
                else:
                    return toolkit.response('User Not Created', 400)
    except json.JSONDecodeError:
        return toolkit.api_error('Error Decoding JSON', 400)
Пример #44
0
def get_repository_images(namespace, repository):
    data = None
    try:
        path = store.index_images_path(namespace, repository)
        data = store.get_content(path)
    except IOError:
        return toolkit.api_error('images not found', 404)
    headers = generate_headers(namespace, repository, 'read')
    return toolkit.response(data, 200, headers, True)
Пример #45
0
def delete_repository(namespace, repository):
    logger.debug("[delete_repository] namespace={0}; repository={1}".format(
                 namespace, repository))
    try:
        store.remove(store.tag_path(namespace, repository))
        #TODO(samalba): Trigger tags_deleted signals
    except OSError:
        return toolkit.api_error('Repository not found', 404)
    return toolkit.response()
Пример #46
0
def get_tag(namespace, repository, tag):
    logger.debug("[get_tag] namespace={0}; repository={1}; tag={2}".format(
                 namespace, repository, tag))
    data = None
    try:
        data = store.get_content(store.tag_path(namespace, repository, tag))
    except IOError:
        return api_error('Tag not found', 404)
    return response(data)
Пример #47
0
def put_image_layer(image_id):
    try:
        json_data = store.get_content(store.image_json_path(image_id))
    except IOError:
        return toolkit.api_error('Image not found', 404)
    layer_path = store.image_layer_path(image_id)
    mark_path = store.image_mark_path(image_id)
    if store.exists(layer_path) and not store.exists(mark_path):
        return toolkit.api_error('Image already exists', 409)
    input_stream = flask.request.stream
    if flask.request.headers.get('transfer-encoding') == 'chunked':
        # Careful, might work only with WSGI servers supporting chunked
        # encoding (Gunicorn)
        input_stream = flask.request.environ['wsgi.input']
    # compute checksums
    csums = []
    sr = toolkit.SocketReader(input_stream)
    tmp, store_hndlr = storage.temp_store_handler()
    sr.add_handler(store_hndlr)
    h, sum_hndlr = checksums.simple_checksum_handler(json_data)
    sr.add_handler(sum_hndlr)
    store.stream_write(layer_path, sr)
    csums.append('sha256:{0}'.format(h.hexdigest()))
    try:
        tmp.seek(0)
        csums.append(checksums.compute_tarsum(tmp, json_data))
        tmp.close()
    except (IOError, checksums.TarError) as e:
        logger.debug('put_image_layer: Error when computing tarsum '
                     '{0}'.format(e))
    try:
        checksum = store.get_content(store.image_checksum_path(image_id))
    except IOError:
        # We don't have a checksum stored yet, that's fine skipping the check.
        # Not removing the mark though, image is not downloadable yet.
        flask.session['checksum'] = csums
        return toolkit.response()
    # We check if the checksums provided matches one the one we computed
    if checksum not in csums:
        logger.debug('put_image_layer: Wrong checksum')
        return toolkit.api_error('Checksum mismatch, ignoring the layer')
    # Checksum is ok, we remove the marker
    store.remove(mark_path)
    return toolkit.response()
Пример #48
0
def get_image_json(image_id):
    try:
        data = store.get_content(store.image_json_path(image_id))
    except IOError:
        return api_error('Image not found', 404)
    checksum_path = store.image_checksum_path(image_id)
    headers = None
    if store.exists(checksum_path):
        headers = {'X-Docker-Checksum': store.get_content(checksum_path)}
    return response(data, headers=headers, raw=True)
Пример #49
0
def get_image_diff(image_id, headers):
    try:
        repository = toolkit.get_repository()
        if repository and store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)

        # first try the cache
        diff_json = layers.get_image_diff_cache(image_id)
        # it the cache misses, request a diff from a worker
        if not diff_json:
            layers.diff_queue.push(image_id)
            # empty response
            diff_json = ""

        return toolkit.response(diff_json, headers=headers, raw=True)
    except IOError:
        return toolkit.api_error('Image not found', 404)
    except tarfile.TarError:
        return toolkit.api_error('Layer format not supported', 400)
Пример #50
0
def put_image_layer(image_id):
    try:
        json_data = store.get_content(store.image_json_path(image_id))
    except IOError:
        return toolkit.api_error("Image not found", 404)
    layer_path = store.image_layer_path(image_id)
    mark_path = store.image_mark_path(image_id)
    if store.exists(layer_path) and not store.exists(mark_path):
        return toolkit.api_error("Image already exists", 409)
    input_stream = flask.request.stream
    if flask.request.headers.get("transfer-encoding") == "chunked":
        # Careful, might work only with WSGI servers supporting chunked
        # encoding (Gunicorn)
        input_stream = flask.request.environ["wsgi.input"]
    # compute checksums
    csums = []
    sr = toolkit.SocketReader(input_stream)
    tmp, store_hndlr = storage.temp_store_handler()
    sr.add_handler(store_hndlr)
    h, sum_hndlr = checksums.simple_checksum_handler(json_data)
    sr.add_handler(sum_hndlr)
    store.stream_write(layer_path, sr)
    csums.append("sha256:{0}".format(h.hexdigest()))
    try:
        tmp.seek(0)
        csums.append(checksums.compute_tarsum(tmp, json_data))
        tmp.close()
    except (IOError, checksums.TarError) as e:
        logger.debug("put_image_layer: Error when computing tarsum " "{0}".format(e))
    try:
        checksum = store.get_content(store.image_checksum_path(image_id))
    except IOError:
        # We don't have a checksum stored yet, that's fine skipping the check.
        # Not removing the mark though, image is not downloadable yet.
        flask.session["checksum"] = csums
        return toolkit.response()
    # We check if the checksums provided matches one the one we computed
    if checksum not in csums:
        logger.debug("put_image_layer: Wrong checksum")
        return toolkit.api_error("Checksum mismatch, ignoring the layer")
    # Checksum is ok, we remove the marker
    store.remove(mark_path)
    return toolkit.response()
Пример #51
0
def get_image_diff(image_id, headers):
    try:
        repository = toolkit.get_repository()
        if repository and store.is_private(*repository):
            return toolkit.api_error('Image not found', 404)

        # first try the cache
        diff_json = layers.get_image_diff_cache(image_id)
        # it the cache misses, request a diff from a worker
        if not diff_json:
            layers.diff_queue.push(image_id)
            # empty response
            diff_json = ""

        return toolkit.response(diff_json, headers=headers, raw=True)
    except IOError:
        return toolkit.api_error('Image not found', 404)
    except tarfile.TarError:
        return toolkit.api_error('Layer format not supported', 400)
Пример #52
0
def get_image_json(image_id):
    try:
        data = store.get_content(store.image_json_path(image_id))
    except IOError:
        return api_error('Image not found', 404)
    checksum_path = store.image_checksum_path(image_id)
    headers = None
    if store.exists(checksum_path):
        headers = {'X-Docker-Checksum': store.get_content(checksum_path)}
    return response(data, headers=headers, raw=True)
Пример #53
0
def _get_tags(namespace, repository):
    logger.debug("[get_tags] namespace={0}; repository={1}".format(namespace,
                 repository))
    try:
        data = {tag_name: tag_content
                for tag_name, tag_content
                in get_tags(namespace=namespace, repository=repository)}
    except OSError:
        return toolkit.api_error('Repository not found', 404)
    return toolkit.response(data)
Пример #54
0
def delete_tag(namespace, repository, tag):
    logger.debug("[delete_tag] namespace={0}; repository={1}; tag={2}".format(
                 namespace, repository, tag))
    try:
        store.remove(store.tag_path(namespace, repository, tag))
        sender = flask.current_app._get_current_object()
        signals.tag_deleted.send(sender, namespace=namespace,
                                 repository=repository, tag=tag)
    except OSError:
        return toolkit.api_error('Tag not found', 404)
    return toolkit.response()
Пример #55
0
def get_tags(namespace, repository):
    data = {}
    try:
        for fname in store.list_directory(store.tag_path(namespace, repository)):
            tag_name = fname.split('/').pop()
            if not tag_name.startswith('tag_'):
                continue
            data[tag_name[4:]] = store.get_content(fname)
    except OSError:
        return api_error('Repository not found', 404)
    return response(data)
Пример #56
0
def put_image_layer(image_id):
    try:
        json_data = store.get_content(store.image_json_path(image_id))
    except IOError:
        return api_error('Image not found', 404)
    layer_path = store.image_layer_path(image_id)
    mark_path = store.image_mark_path(image_id)
    if store.exists(layer_path) and not store.exists(mark_path):
        return api_error('Image already exists', 409)
    input_stream = request.stream
    if request.headers.get('transfer-encoding') == 'chunked':
        # Careful, might work only with WSGI servers supporting chunked
        # encoding (Gunicorn)
        input_stream = request.environ['wsgi.input']
    # compute checksums
    csums = []
    with storage.store_stream(input_stream) as f:
        try:
            csums.append(checksums.compute_simple(f, json_data))
            f.seek(0)
            csums.append(checksums.compute_tarsum(f, json_data))
        except (IOError, checksums.TarError) as e:
            logger.debug('put_image_layer: Error when computing checksum '
                         '{0}'.format(e))
        f.seek(0)
        store.stream_write(layer_path, f)
    try:
        checksum = store.get_content(store.image_checksum_path(image_id))
    except IOError:
        # We don't have a checksum stored yet, that's fine skipping the check.
        # Not removing the mark though, image is not downloadable yet.
        session['checksum'] = csums
        return response()
    # We check if the checksums provided matches one the one we computed
    if checksum not in csums:
        logger.debug('put_image_layer: Wrong checksum')
        return api_error('Checksum mismatch, ignoring the layer')
    # Checksum is ok, we remove the marker
    store.remove(mark_path)
    return response()
Пример #57
0
def put_image_checksum(image_id):
    if toolkit.DockerVersion() < '0.10':
        checksum = flask.request.headers.get('X-Docker-Checksum')
    else:
        checksum = flask.request.headers.get('X-Docker-Checksum-Payload')
    if not checksum:
        return toolkit.api_error('Missing Image\'s checksum')
    if not flask.session.get('checksum'):
        return toolkit.api_error('Checksum not found in Cookie')
    if not store.exists(store.image_json_path(image_id)):
        return toolkit.api_error('Image not found', 404)
    mark_path = store.image_mark_path(image_id)
    if not store.exists(mark_path):
        return toolkit.api_error('Cannot set this image checksum', 409)
    err = store_checksum(image_id, checksum)
    if err:
        return toolkit.api_error(err)
    if checksum not in flask.session.get('checksum', []):
        logger.debug('put_image_checksum: Wrong checksum. '
                     'Provided: {0}; Expected: {1}'.format(
                         checksum, flask.session.get('checksum')))
        return toolkit.api_error('Checksum mismatch')
    # Checksum is ok, we remove the marker
    store.remove(mark_path)
    # We trigger a task on the diff worker if it's running
    if cache.redis_conn:
        layers.diff_queue.push(image_id)
    return toolkit.response()
Пример #58
0
def get_image_json(image_id, headers):
    try:
        data = store.get_content(store.image_json_path(image_id))
    except IOError:
        return toolkit.api_error('Image not found', 404)
    try:
        size = store.get_size(store.image_layer_path(image_id))
        headers['X-Docker-Size'] = str(size)
    except OSError:
        pass
    checksum_path = store.image_checksum_path(image_id)
    if store.exists(checksum_path):
        headers['X-Docker-Checksum'] = store.get_content(checksum_path)
    return toolkit.response(data, headers=headers, raw=True)