This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/endpoints/verbs.py

64 lines
2.4 KiB
Python
Raw Normal View History

import logging
import json
import hashlib
from flask import (make_response, request, session, Response, redirect,
Blueprint, abort, send_file, make_response)
from app import storage as store, app
from auth.auth import process_auth
from auth.permissions import ReadRepositoryPermission
from data import model
from endpoints.registry import set_cache_headers
from util.gzipwrap import GzipWrap
from util.streamlayerformat import StreamLayerMerger
from werkzeug.wsgi import wrap_file
verbs = Blueprint('verbs', __name__)
logger = logging.getLogger(__name__)
@verbs.route('/<namespace>/<repository>/<tag>/squash', methods=['GET'])
@process_auth
@set_cache_headers
def get_squashed_tag(namespace, repository, tag, headers):
permission = ReadRepositoryPermission(namespace, repository)
if permission.can() or model.repository_is_public(namespace, repository):
# Lookup the requested tag.
tag_image = model.get_tag_image(namespace, repository, tag)
if not tag_image:
abort(404)
# Lookup the tag's image and storage.
repo_image = model.get_repo_image(namespace, repository, tag_image.docker_image_id)
if not repo_image:
abort(404)
# Calculate a synthetic image ID by hashing the *image storage ID* with our
# secret. This is done to prevent the ID being guessable/overwritable by
# external pushes.
unhashed = str(repo_image.storage.id) + ':' + app.config['SECRET_KEY']
synthetic_image_id = hashlib.sha256(unhashed).hexdigest()
# Load the ancestry for the image.
uuid = repo_image.storage.uuid
ancestry_data = store.get_content(repo_image.storage.locations, store.image_ancestry_path(uuid))
full_image_list = json.loads(ancestry_data)
def get_next_layer():
for current_image_id in full_image_list:
current_image_entry = model.get_repo_image(namespace, repository, current_image_id)
current_image_path = store.image_layer_path(current_image_entry.storage.uuid)
current_image_stream = store.stream_read_file(current_image_entry.storage.locations,
current_image_path)
logger.debug('Returning image layer %s: %s' % (current_image_id, current_image_path))
yield current_image_stream
stream = GzipWrap(StreamLayerMerger(get_next_layer).get_generator())
return send_file(stream)
abort(403)