Merge pull request #3306 from quay/fix-manifest-ui
Fix manifest UI page to properly show the layers of manifests and show manifest lists
This commit is contained in:
commit
fc691cefb4
15 changed files with 186 additions and 91 deletions
|
@ -13,6 +13,9 @@ class RegistryModelProxy(object):
|
|||
self._model = oci_model if os.getenv('OCI_DATA_MODEL') == 'true' else pre_oci_model
|
||||
|
||||
def setup_split(self, v22_whitelist):
|
||||
if os.getenv('OCI_DATA_MODEL') == 'true':
|
||||
return
|
||||
|
||||
logger.info('===============================')
|
||||
logger.info('Enabling split registry model with namespace whitelist `%s`', v22_whitelist)
|
||||
logger.info('===============================')
|
||||
|
|
|
@ -207,7 +207,14 @@ class Manifest(datatype('Manifest', ['digest', 'media_type', 'manifest_bytes']))
|
|||
@property
|
||||
@requiresinput('legacy_image')
|
||||
def legacy_image(self, legacy_image):
|
||||
""" Returns the legacy Docker V1-style image for this manifest. Note that this
|
||||
""" Returns the legacy Docker V1-style image for this manifest.
|
||||
"""
|
||||
return legacy_image
|
||||
|
||||
@property
|
||||
@optionalinput('legacy_image')
|
||||
def legacy_image_if_present(self, legacy_image):
|
||||
""" Returns the legacy Docker V1-style image for this manifest. Note that this
|
||||
will be None for manifests that point to other manifests instead of images.
|
||||
"""
|
||||
return legacy_image
|
||||
|
|
|
@ -194,13 +194,21 @@ class RegistryDataInterface(object):
|
|||
def get_manifest_local_blobs(self, manifest, include_placements=False):
|
||||
""" Returns the set of local blobs for the given manifest or None if none. """
|
||||
|
||||
@abstractmethod
|
||||
def list_manifest_layers(self, manifest, storage, include_placements=False):
|
||||
""" Returns an *ordered list* of the layers found in the manifest, starting at the base
|
||||
and working towards the leaf, including the associated Blob and its placements
|
||||
(if specified). The layer information in `layer_info` will be of type
|
||||
`image.docker.types.ManifestImageLayer`. Should not be called for a manifest list.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def list_parsed_manifest_layers(self, repository_ref, parsed_manifest, storage,
|
||||
include_placements=False):
|
||||
""" Returns an *ordered list* of the layers found in the parsed manifest, starting at the base
|
||||
and working towards the leaf, including the associated Blob and its placements
|
||||
(if specified). The layer information in `layer_info` will be of type
|
||||
`image.docker.types.ManifestImageLayer`.
|
||||
`image.docker.types.ManifestImageLayer`. Should not be called for a manifest list.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
|
|
|
@ -115,7 +115,7 @@ class OCIModel(SharedModel, RegistryDataInterface):
|
|||
legacy_image_id = database.ManifestLegacyImage.get(manifest=manifest).image.docker_image_id
|
||||
legacy_image = self.get_legacy_image(repository_ref, legacy_image_id, include_parents=True)
|
||||
except database.ManifestLegacyImage.DoesNotExist:
|
||||
return None
|
||||
pass
|
||||
|
||||
return Manifest.for_manifest(manifest, legacy_image)
|
||||
|
||||
|
@ -414,11 +414,7 @@ class OCIModel(SharedModel, RegistryDataInterface):
|
|||
legacy_image = oci.shared.get_legacy_image_for_manifest(manifest)
|
||||
return Manifest.for_manifest(manifest, LegacyImage.for_image(legacy_image))
|
||||
|
||||
def list_manifest_layers(self, manifest, include_placements=False):
|
||||
""" Returns an *ordered list* of the layers found in the manifest, starting at the base and
|
||||
working towards the leaf, including the associated Blob and its placements (if specified).
|
||||
Returns None if the manifest could not be parsed and validated.
|
||||
"""
|
||||
def list_manifest_layers(self, manifest, storage, include_placements=False):
|
||||
try:
|
||||
manifest_obj = database.Manifest.get(id=manifest._db_id)
|
||||
except database.Manifest.DoesNotExist:
|
||||
|
@ -431,8 +427,8 @@ class OCIModel(SharedModel, RegistryDataInterface):
|
|||
logger.exception('Could not parse and validate manifest `%s`', manifest._db_id)
|
||||
return None
|
||||
|
||||
return self._list_manifest_layers(manifest_obj.repository_id, parsed, include_placements,
|
||||
by_manifest=True)
|
||||
return self._list_manifest_layers(manifest_obj.repository_id, parsed, storage,
|
||||
include_placements, by_manifest=True)
|
||||
|
||||
def lookup_derived_image(self, manifest, verb, varying_metadata=None, include_placements=False):
|
||||
"""
|
||||
|
|
|
@ -479,11 +479,7 @@ class PreOCIModel(SharedModel, RegistryDataInterface):
|
|||
|
||||
return Manifest.for_tag_manifest(tag_manifest)
|
||||
|
||||
def list_manifest_layers(self, manifest, include_placements=False):
|
||||
""" Returns an *ordered list* of the layers found in the manifest, starting at the base and
|
||||
working towards the leaf, including the associated Blob and its placements (if specified).
|
||||
Returns None if the manifest could not be parsed and validated.
|
||||
"""
|
||||
def list_manifest_layers(self, manifest, storage, include_placements=False):
|
||||
try:
|
||||
tag_manifest = database.TagManifest.get(id=manifest._db_id)
|
||||
except database.TagManifest.DoesNotExist:
|
||||
|
@ -497,7 +493,7 @@ class PreOCIModel(SharedModel, RegistryDataInterface):
|
|||
return None
|
||||
|
||||
repo_ref = RepositoryReference.for_id(tag_manifest.tag.repository_id)
|
||||
return self.list_parsed_manifest_layers(repo_ref, parsed, include_placements)
|
||||
return self.list_parsed_manifest_layers(repo_ref, parsed, storage, include_placements)
|
||||
|
||||
def lookup_derived_image(self, manifest, verb, varying_metadata=None, include_placements=False):
|
||||
"""
|
||||
|
|
|
@ -12,6 +12,7 @@ from data.registry_model.datatype import FromDictionaryException
|
|||
from data.registry_model.datatypes import (RepositoryReference, Blob, TorrentInfo, BlobUpload,
|
||||
LegacyImage, ManifestLayer, DerivedImage)
|
||||
from image.docker.schema1 import ManifestException, DockerSchema1ManifestBuilder
|
||||
from image.docker.schema2 import EMPTY_LAYER_BLOB_DIGEST
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -344,14 +345,23 @@ class SharedModel:
|
|||
working towards the leaf, including the associated Blob and its placements (if specified).
|
||||
Returns None if the manifest could not be parsed and validated.
|
||||
"""
|
||||
assert not parsed.is_manifest_list
|
||||
|
||||
retriever = RepositoryContentRetriever(repo_id, storage)
|
||||
requires_empty_blob = parsed.get_requires_empty_layer_blob(retriever)
|
||||
|
||||
storage_map = {}
|
||||
if parsed.local_blob_digests:
|
||||
blob_digests = list(parsed.local_blob_digests)
|
||||
if requires_empty_blob:
|
||||
blob_digests.append(EMPTY_LAYER_BLOB_DIGEST)
|
||||
|
||||
if blob_digests:
|
||||
blob_query = model.storage.lookup_repo_storages_by_content_checksum(repo_id,
|
||||
parsed.local_blob_digests,
|
||||
blob_digests,
|
||||
by_manifest=by_manifest)
|
||||
storage_map = {blob.content_checksum: blob for blob in blob_query}
|
||||
|
||||
retriever = RepositoryContentRetriever(repo_id, storage)
|
||||
|
||||
layers = parsed.get_layers(retriever)
|
||||
if layers is None:
|
||||
logger.error('Could not load layers for manifest `%s`', parsed.digest)
|
||||
|
|
Reference in a new issue