Support pulling of schema2 manifests directly via a manifest list tag

This change ensures that if a manifest list is requested with an accepts header for a *schema 2* manifest, the legacy manifest (if any) is returned as schema 2 if it was pushed as a schema 2 manifest (rather than being auto-converted to schema 1)
This commit is contained in:
Joseph Schorr 2018-12-06 12:40:34 -05:00
parent a35982f2be
commit 3c2e050593
14 changed files with 215 additions and 15 deletions

View file

@ -6,16 +6,16 @@ from flask import request, url_for, Response
import features
from app import app, metric_queue, storage, model_cache
from app import app, metric_queue, storage
from auth.registry_jwt_auth import process_registry_jwt_auth
from digest import digest_tools
from data.registry_model import registry_model
from endpoints.decorators import anon_protect, parse_repository_name
from endpoints.v2 import v2_bp, require_repo_read, require_repo_write
from endpoints.v2.errors import (ManifestInvalid, ManifestUnknown, TagInvalid,
NameInvalid, TagExpired, NameUnknown)
from endpoints.v2.errors import (ManifestInvalid, ManifestUnknown, NameInvalid, TagExpired,
NameUnknown)
from image.docker import ManifestException
from image.docker.schema1 import DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE, DockerSchema1Manifest
from image.docker.schema1 import DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE
from image.docker.schema2 import DOCKER_SCHEMA2_CONTENT_TYPES, OCI_CONTENT_TYPES
from image.docker.schemas import parse_manifest_from_bytes
from notifications import spawn_notification
@ -62,8 +62,8 @@ def fetch_manifest_by_tagname(namespace_name, repo_name, manifest_ref):
logger.exception('Got exception when trying to parse manifest `%s`', manifest_ref)
raise ManifestInvalid()
supported = _rewrite_to_schema1_if_necessary(namespace_name, repo_name, manifest_ref, manifest,
parsed)
supported = _rewrite_schema_if_necessary(namespace_name, repo_name, manifest_ref, manifest,
parsed)
if supported is None:
raise ManifestUnknown()
@ -101,8 +101,8 @@ def fetch_manifest_by_digest(namespace_name, repo_name, manifest_ref):
logger.exception('Got exception when trying to parse manifest `%s`', manifest_ref)
raise ManifestInvalid()
supported = _rewrite_to_schema1_if_necessary(namespace_name, repo_name, '$digest', manifest,
parsed)
supported = _rewrite_schema_if_necessary(namespace_name, repo_name, '$digest', manifest,
parsed)
if supported is None:
raise ManifestUnknown()
@ -115,7 +115,7 @@ def fetch_manifest_by_digest(namespace_name, repo_name, manifest_ref):
})
def _rewrite_to_schema1_if_necessary(namespace_name, repo_name, tag_name, manifest, parsed):
def _rewrite_schema_if_necessary(namespace_name, repo_name, tag_name, manifest, parsed):
# As per the Docker protocol, if the manifest is not schema version 1 and the manifest's
# media type is not in the Accept header, we return a schema 1 version of the manifest for
# the amd64+linux platform, if any, or None if none.
@ -124,6 +124,12 @@ def _rewrite_to_schema1_if_necessary(namespace_name, repo_name, tag_name, manife
if parsed.media_type in mimetypes:
return parsed
converted = registry_model.convert_manifest(manifest, namespace_name, repo_name, tag_name,
mimetypes, storage)
if converted is not None:
return converted
# For back-compat, we always default to schema 1 if the manifest could not be converted.
return registry_model.get_schema1_parsed_manifest(manifest, namespace_name, repo_name, tag_name,
storage)