Unify the get_layers calls across all implements of manifest schemas to ensure we have a common type returned
Also renames some methods to make it more clear what kind of information they return
This commit is contained in:
parent
180d8847db
commit
4e1ff90cb2
17 changed files with 210 additions and 124 deletions
|
@ -195,10 +195,12 @@ class RegistryDataInterface(object):
|
|||
""" Returns the set of local blobs for the given manifest or None if none. """
|
||||
|
||||
@abstractmethod
|
||||
def list_parsed_manifest_layers(self, repository_ref, parsed_manifest, include_placements=False):
|
||||
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).
|
||||
(if specified). The layer information in `layer_info` will be of type
|
||||
`image.docker.types.ManifestImageLayer`.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
|
|
|
@ -523,12 +523,14 @@ class OCIModel(SharedModel, RegistryDataInterface):
|
|||
storage_path=model.storage.get_layer_path(image_storage),
|
||||
placements=placements)
|
||||
|
||||
def list_parsed_manifest_layers(self, repository_ref, parsed_manifest, include_placements=False):
|
||||
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).
|
||||
"""
|
||||
return self._list_manifest_layers(repository_ref._db_id, parsed_manifest, include_placements,
|
||||
return self._list_manifest_layers(repository_ref._db_id, parsed_manifest, storage,
|
||||
include_placements=include_placements,
|
||||
by_manifest=True)
|
||||
|
||||
def get_manifest_local_blobs(self, manifest, include_placements=False):
|
||||
|
|
|
@ -577,12 +577,14 @@ class PreOCIModel(SharedModel, RegistryDataInterface):
|
|||
storage_path=model.storage.get_layer_path(image_storage),
|
||||
placements=placements)
|
||||
|
||||
def list_parsed_manifest_layers(self, repository_ref, parsed_manifest, include_placements=False):
|
||||
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).
|
||||
"""
|
||||
return self._list_manifest_layers(repository_ref._db_id, parsed_manifest, include_placements)
|
||||
return self._list_manifest_layers(repository_ref._db_id, parsed_manifest, storage,
|
||||
include_placements=include_placements)
|
||||
|
||||
def get_manifest_local_blobs(self, manifest, include_placements=False):
|
||||
""" Returns the set of local blobs for the given manifest or None if none. """
|
||||
|
|
|
@ -7,6 +7,7 @@ from collections import defaultdict
|
|||
from data import database
|
||||
from data import model
|
||||
from data.cache import cache_key
|
||||
from data.model.oci.retriever import RepositoryContentRetriever
|
||||
from data.registry_model.datatype import FromDictionaryException
|
||||
from data.registry_model.datatypes import (RepositoryReference, Blob, TorrentInfo, BlobUpload,
|
||||
LegacyImage, ManifestLayer, DerivedImage)
|
||||
|
@ -316,7 +317,8 @@ class SharedModel:
|
|||
|
||||
return blobs
|
||||
|
||||
def _list_manifest_layers(self, repo_id, parsed, include_placements=False, by_manifest=False):
|
||||
def _list_manifest_layers(self, repo_id, parsed, storage, include_placements=False,
|
||||
by_manifest=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.
|
||||
|
@ -328,15 +330,21 @@ class SharedModel:
|
|||
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)
|
||||
return None
|
||||
|
||||
manifest_layers = []
|
||||
for layer in parsed.layers:
|
||||
for layer in layers:
|
||||
if layer.is_remote:
|
||||
manifest_layers.append(ManifestLayer(layer, None))
|
||||
continue
|
||||
|
||||
digest_str = str(layer.digest)
|
||||
digest_str = str(layer.blob_digest)
|
||||
if digest_str not in storage_map:
|
||||
logger.error('Missing digest `%s` for manifest `%s`', layer.digest, parsed.digest)
|
||||
logger.error('Missing digest `%s` for manifest `%s`', layer.blob_digest, parsed.digest)
|
||||
return None
|
||||
|
||||
image_storage = storage_map[digest_str]
|
||||
|
|
|
@ -21,6 +21,7 @@ from data.registry_model.registry_pre_oci_model import PreOCIModel
|
|||
from data.registry_model.registry_oci_model import OCIModel
|
||||
from data.registry_model.datatypes import RepositoryReference
|
||||
from data.registry_model.blobuploader import upload_blob, BlobUploadSettings
|
||||
from image.docker.types import ManifestImageLayer
|
||||
from image.docker.schema1 import DockerSchema1ManifestBuilder
|
||||
from image.docker.schema2.manifest import DockerSchema2ManifestBuilder
|
||||
|
||||
|
@ -474,19 +475,14 @@ def test_layers_and_blobs(repo_namespace, repo_name, registry_model):
|
|||
parsed = manifest.get_parsed_manifest()
|
||||
assert parsed
|
||||
|
||||
layers = registry_model.list_parsed_manifest_layers(repository_ref, parsed)
|
||||
layers = registry_model.list_parsed_manifest_layers(repository_ref, parsed, storage)
|
||||
assert layers
|
||||
|
||||
layers = registry_model.list_parsed_manifest_layers(repository_ref, parsed,
|
||||
layers = registry_model.list_parsed_manifest_layers(repository_ref, parsed, storage,
|
||||
include_placements=True)
|
||||
assert layers
|
||||
|
||||
parsed_layers = list(manifest.get_parsed_manifest().layers)
|
||||
assert len(layers) == len(parsed_layers)
|
||||
|
||||
for index, manifest_layer in enumerate(layers):
|
||||
assert manifest_layer.layer_info == parsed_layers[index]
|
||||
assert manifest_layer.blob.digest == str(parsed_layers[index].digest)
|
||||
assert manifest_layer.blob.storage_path
|
||||
assert manifest_layer.blob.placements
|
||||
|
||||
|
@ -494,6 +490,7 @@ def test_layers_and_blobs(repo_namespace, repo_name, registry_model):
|
|||
assert repo_blob.digest == manifest_layer.blob.digest
|
||||
|
||||
assert manifest_layer.estimated_size(1) is not None
|
||||
assert isinstance(manifest_layer.layer_info, ManifestImageLayer)
|
||||
|
||||
blobs = registry_model.get_manifest_local_blobs(manifest, include_placements=True)
|
||||
assert {b.digest for b in blobs} == set(parsed.local_blob_digests)
|
||||
|
@ -532,7 +529,8 @@ def test_manifest_remote_layers(oci_model):
|
|||
assert created_manifest
|
||||
|
||||
layers = oci_model.list_parsed_manifest_layers(repository_ref,
|
||||
created_manifest.get_parsed_manifest())
|
||||
created_manifest.get_parsed_manifest(),
|
||||
storage)
|
||||
assert len(layers) == 1
|
||||
assert layers[0].layer_info.is_remote
|
||||
assert layers[0].layer_info.urls == ['http://hello/world']
|
||||
|
|
Reference in a new issue