Fixes to ensuring existing code can process schema 2 manifests

This commit is contained in:
Joseph Schorr 2018-11-13 17:13:51 +02:00
parent 9474fb7833
commit 7b9f56eff3
10 changed files with 91 additions and 21 deletions

View file

@ -282,7 +282,7 @@ class RegistryDataInterface(object):
"""
Mounts the blob from another repository into the specified target repository, and adds an
expiration before that blob is automatically GCed. This function is useful during push
operations if an existing blob from another repositroy is being pushed. Returns False if
operations if an existing blob from another repository is being pushed. Returns False if
the mounting fails. Note that this function does *not* check security for mounting the blob
and the caller is responsible for doing this check (an example can be found in
endpoints/v2/blob.py).
@ -293,3 +293,7 @@ class RegistryDataInterface(object):
"""
Sets the expiration on all tags that point to the given manifest to that specified.
"""
@abstractmethod
def get_schema1_parsed_manifest(self, manifest, namespace_name, repo_name, tag_name, storage):
""" Returns the schema 1 version of this manifest, or None if none. """

View file

@ -8,9 +8,11 @@ from data import model
from data.model import oci, DataModelException
from data.database import db_transaction, Image
from data.registry_model.interface import RegistryDataInterface
from data.registry_model.datatypes import Tag, Manifest, LegacyImage, Label, SecurityScanStatus
from data.registry_model.datatypes import (Tag, Manifest, LegacyImage, Label, SecurityScanStatus,
RepositoryReference)
from data.registry_model.shared import SharedModel
from data.registry_model.label_handlers import apply_label_to_manifest
from image.docker import ManifestException
logger = logging.getLogger(__name__)
@ -420,5 +422,27 @@ class OCIModel(SharedModel, RegistryDataInterface):
"""
oci.tag.set_tag_expiration_sec_for_manifest(manifest._db_id, expiration_sec)
def get_schema1_parsed_manifest(self, manifest, namespace_name, repo_name, tag_name, storage):
""" Returns the schema 1 manifest for this manifest, or None if none. """
try:
parsed = manifest.get_parsed_manifest()
except ManifestException:
return None
try:
manifest_row = database.Manifest.get(id=manifest._db_id)
except database.Manifest.DoesNotExist:
return None
repository_ref = RepositoryReference.for_id(manifest_row.repository_id)
def _lookup_blob(digest):
blob = self.get_repo_blob_by_digest(repository_ref, digest, include_placements=True)
if blob is None:
return None
return storage.get_content(blob.placements, blob.storage_path)
return parsed.get_v1_compatible_manifest(namespace_name, repo_name, tag_name, _lookup_blob)
oci_model = OCIModel()

View file

@ -527,4 +527,12 @@ class PreOCIModel(SharedModel, RegistryDataInterface):
model.tag.set_tag_expiration_for_manifest(tag_manifest, expiration_sec)
def get_schema1_parsed_manifest(self, manifest, namespace_name, repo_name, tag_name, storage):
""" Returns the schema 1 version of this manifest, or None if none. """
try:
return manifest.get_parsed_manifest()
except ManifestException:
return None
pre_oci_model = PreOCIModel()

View file

@ -317,7 +317,8 @@ class SharedModel:
logger.exception('Could not parse and validate manifest `%s`', manifest._db_id)
return None
blob_query = model.storage.lookup_repo_storages_by_content_checksum(repo_id, parsed.checksums)
blob_query = model.storage.lookup_repo_storages_by_content_checksum(repo_id,
parsed.blob_digests)
storage_map = {blob.content_checksum: blob for blob in blob_query}
manifest_layers = []

View file

@ -95,6 +95,9 @@ def test_lookup_manifests(repo_namespace, repo_name, registry_model):
assert found.legacy_image
assert found.legacy_image.parents
schema1_parsed = registry_model.get_schema1_parsed_manifest(found, 'foo', 'bar', 'baz', storage)
assert schema1_parsed is not None
def test_lookup_unknown_manifest(registry_model):
repo = model.repository.get_repository('devtable', 'simple')