Skip to content

Commit

Permalink
registry: update blob mount behaviour when from parameter is missing (P…
Browse files Browse the repository at this point in the history
…ROJQUAY-2570) (#899)

Update the behaviour when attempting to mount existing blob whenever
the `from` parameter is missing. Currently, Quay throws an Bad Request
error whenever the `from parameter is missing. However, according to
the specs (Docker Registry and OCI dist-spec), we should be falling
back to the default upload behaviour.

References:
  - https://docs.docker.com/registry/spec/api/#pushing-an-image
  -
  https://github.com/opencontainers/distribution-spec/blob/main/spec.md#mounting-a-blob-from-another-repository
  - https://github.com/opencontainers/distribution-spec/pull/275/files
  • Loading branch information
kleesc authored Sep 23, 2021
1 parent c7c4c0d commit 32322bc
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 14 deletions.
4 changes: 3 additions & 1 deletion endpoints/v2/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ def _try_to_mount_blob(repository_ref, mount_blob_digest):
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")
# If we cannot mount the blob, fall back to the standard upload behavior,
# since we don't support automatic mount origin discovery across all repos.
return None

# Ensure the user has access to the repository.
logger.debug(
Expand Down
33 changes: 20 additions & 13 deletions endpoints/v2/test/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,28 @@ def test_blob_caching(method, endpoint, client, app):


@pytest.mark.parametrize(
"mount_digest, source_repo, username, expect_success",
"mount_digest, source_repo, username, include_from_param, expected_code",
[
# Unknown blob.
("sha256:unknown", "devtable/simple", "devtable", False),
("sha256:unknown", "devtable/simple", "devtable", True, 202),
("sha256:unknown", "devtable/simple", "devtable", False, 202),
# Blob not in repo.
("sha256:" + hashlib.sha256(b"a").hexdigest(), "devtable/complex", "devtable", False),
# Blob in repo.
("sha256:" + hashlib.sha256(b"b").hexdigest(), "devtable/complex", "devtable", True),
# No access to repo.
("sha256:" + hashlib.sha256(b"b").hexdigest(), "devtable/complex", "public", False),
# Public repo.
("sha256:" + hashlib.sha256(b"c").hexdigest(), "public/publicrepo", "devtable", True),
("sha256:" + hashlib.sha256(b"a").hexdigest(), "devtable/complex", "devtable", True, 202),
("sha256:" + hashlib.sha256(b"a").hexdigest(), "devtable/complex", "devtable", False, 202),
# # Blob in repo.
("sha256:" + hashlib.sha256(b"b").hexdigest(), "devtable/complex", "devtable", True, 201),
("sha256:" + hashlib.sha256(b"b").hexdigest(), "devtable/complex", "devtable", False, 202),
# # No access to repo.
("sha256:" + hashlib.sha256(b"b").hexdigest(), "devtable/complex", "public", True, 202),
("sha256:" + hashlib.sha256(b"b").hexdigest(), "devtable/complex", "public", False, 202),
# # Public repo.
("sha256:" + hashlib.sha256(b"c").hexdigest(), "public/publicrepo", "devtable", True, 201),
("sha256:" + hashlib.sha256(b"c").hexdigest(), "public/publicrepo", "devtable", False, 202),
],
)
def test_blob_mounting(mount_digest, source_repo, username, expect_success, client, app):
def test_blob_mounting(
mount_digest, source_repo, username, include_from_param, expected_code, client, app
):
location = ImageStorageLocation.get(name="local_us")

# Store and link some blobs.
Expand All @@ -109,8 +116,9 @@ def test_blob_mounting(mount_digest, source_repo, username, expect_success, clie
params = {
"repository": "devtable/building",
"mount": mount_digest,
"from": source_repo,
}
if include_from_param:
params["from"] = source_repo

user = model.user.get_user(username)
access = [
Expand Down Expand Up @@ -139,7 +147,6 @@ def test_blob_mounting(mount_digest, source_repo, username, expect_success, clie
"Authorization": "Bearer %s" % token.decode("ascii"),
}

expected_code = 201 if expect_success else 202
conduct_call(
client,
"v2.start_blob_upload",
Expand All @@ -152,7 +159,7 @@ def test_blob_mounting(mount_digest, source_repo, username, expect_success, clie

repository = model.repository.get_repository("devtable", "building")

if expect_success:
if expected_code == 201:
# Ensure the blob now exists under the repo.
assert model.oci.blob.get_repository_blob_by_digest(repository, mount_digest)
else:
Expand Down

0 comments on commit 32322bc

Please sign in to comment.