Skip parsing the manifest where applicable

Instead of always parsing (like we did previously), we now only parse the manifest if conversion is necessary. This should save significant CPU.
This commit is contained in:
Joseph Schorr 2019-01-11 15:24:21 -05:00
parent 396ce21020
commit 7f068c3fc3

View file

@ -57,15 +57,9 @@ def fetch_manifest_by_tagname(namespace_name, repo_name, manifest_ref):
# Something went wrong.
raise ManifestInvalid()
try:
parsed = manifest.get_parsed_manifest()
except ManifestException:
logger.exception('Got exception when trying to parse manifest `%s`', manifest_ref)
raise ManifestInvalid()
supported = _rewrite_schema_if_necessary(namespace_name, repo_name, manifest_ref, manifest,
parsed)
if supported is None:
manifest_bytes, manifest_digest, manifest_media_type = _rewrite_schema_if_necessary(
namespace_name, repo_name, manifest_ref, manifest)
if manifest_bytes is None:
raise ManifestUnknown()
track_and_log('pull_repo', repository_ref, analytics_name='pull_repo_100x', analytics_sample=0.01,
@ -73,11 +67,11 @@ def fetch_manifest_by_tagname(namespace_name, repo_name, manifest_ref):
metric_queue.repository_pull.Inc(labelvalues=[namespace_name, repo_name, 'v2', True])
return Response(
supported.bytes.as_unicode(),
manifest_bytes.as_unicode(),
status=200,
headers={
'Content-Type': '%s; charset=utf-8' % supported.media_type,
'Docker-Content-Digest': supported.digest,
'Content-Type': '%s; charset=utf-8' % manifest_media_type,
'Docker-Content-Digest': manifest_digest,
},
)
@ -96,43 +90,43 @@ def fetch_manifest_by_digest(namespace_name, repo_name, manifest_ref):
if manifest is None:
raise ManifestUnknown()
try:
parsed = manifest.get_parsed_manifest()
except ManifestException:
logger.exception('Got exception when trying to parse manifest `%s`', manifest_ref)
raise ManifestInvalid()
supported = _rewrite_schema_if_necessary(namespace_name, repo_name, '$digest', manifest,
parsed)
if supported is None:
manifest_bytes, manifest_digest, manifest_media_type = _rewrite_schema_if_necessary(
namespace_name, repo_name, '$digest', manifest)
if manifest_digest is None:
raise ManifestUnknown()
track_and_log('pull_repo', repository_ref, manifest_digest=manifest_ref)
metric_queue.repository_pull.Inc(labelvalues=[namespace_name, repo_name, 'v2', True])
return Response(supported.bytes.as_unicode(), status=200, headers={
'Content-Type': '%s; charset=utf-8' % supported.media_type,
'Docker-Content-Digest': supported.digest,
return Response(manifest_bytes.as_unicode(), status=200, headers={
'Content-Type': '%s; charset=utf-8' % manifest_media_type,
'Docker-Content-Digest': manifest_digest,
})
def _rewrite_schema_if_necessary(namespace_name, repo_name, tag_name, manifest, parsed):
def _rewrite_schema_if_necessary(namespace_name, repo_name, tag_name, manifest):
# 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.
# See: https://docs.docker.com/registry/spec/manifest-v2-2
mimetypes = [mimetype for mimetype, _ in request.accept_mimetypes]
if parsed.media_type in mimetypes:
return parsed
if manifest.media_type in mimetypes:
return manifest.internal_manifest_bytes, manifest.digest, manifest.media_type
logger.debug('Manifest `%s` not compatible against %s; checking for conversion', manifest.digest,
request.accept_mimetypes)
converted = registry_model.convert_manifest(manifest, namespace_name, repo_name, tag_name,
mimetypes, storage)
if converted is not None:
return converted
return converted.bytes, converted.digest, converted.media_type
# 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)
schema1 = registry_model.get_schema1_parsed_manifest(manifest, namespace_name, repo_name,
tag_name, storage)
if schema1 is None:
return None, None, None
return schema1.bytes, schema1.digest, schema1.media_type
def _reject_manifest2_schema2(func):