Change manifest API endpoints to use new registry data interface
This commit is contained in:
parent
6c494f4917
commit
a0a6a3d67d
7 changed files with 200 additions and 247 deletions
|
@ -10,14 +10,16 @@ class RepositoryReference(datatype('Repository', [])):
|
|||
return RepositoryReference(db_id=repo_obj.id)
|
||||
|
||||
|
||||
class Label(datatype('Label', ['key', 'value'])):
|
||||
class Label(datatype('Label', ['key', 'value', 'uuid', 'source_type_name', 'media_type_name'])):
|
||||
""" Label represents a label on a manifest. """
|
||||
@classmethod
|
||||
def for_label(cls, label):
|
||||
if label is None:
|
||||
return None
|
||||
|
||||
return Label(db_id=label.id, key=label.key, value=label.value)
|
||||
return Label(db_id=label.id, key=label.key, value=label.value,
|
||||
uuid=label.uuid, media_type_name=label.media_type.name,
|
||||
source_type_name=label.source_type.name)
|
||||
|
||||
|
||||
class Tag(datatype('Tag', ['name'])):
|
||||
|
@ -30,14 +32,24 @@ class Tag(datatype('Tag', ['name'])):
|
|||
return Tag(db_id=repository_tag.id, name=repository_tag.name)
|
||||
|
||||
|
||||
class Manifest(datatype('Manifest', ['digest'])):
|
||||
class Manifest(datatype('Manifest', ['digest', 'manifest_bytes'])):
|
||||
""" Manifest represents a manifest in a repository. """
|
||||
@classmethod
|
||||
def for_tag_manifest(cls, tag_manifest):
|
||||
def for_tag_manifest(cls, tag_manifest, legacy_image=None):
|
||||
if tag_manifest is None:
|
||||
return None
|
||||
|
||||
return Manifest(db_id=tag_manifest.id, digest=tag_manifest.digest)
|
||||
return Manifest(db_id=tag_manifest.id, digest=tag_manifest.digest,
|
||||
manifest_bytes=tag_manifest.json_data,
|
||||
inputs=dict(legacy_image=legacy_image))
|
||||
|
||||
@property
|
||||
@requiresinput('legacy_image')
|
||||
def legacy_image(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
|
||||
|
||||
|
||||
class LegacyImage(datatype('LegacyImage', ['docker_image_id', 'created', 'comment', 'command',
|
||||
|
|
|
@ -34,10 +34,6 @@ class RegistryDataInterface(object):
|
|||
""" Looks up the manifest with the given digest under the given repository and returns it
|
||||
or None if none. """
|
||||
|
||||
@abstractmethod
|
||||
def create_manifest_label(self, manifest, key, value, source_type_name, media_type_name=None):
|
||||
""" Creates a label on the manifest with the given key and value. """
|
||||
|
||||
@abstractmethod
|
||||
def get_legacy_images(self, repository_ref):
|
||||
"""
|
||||
|
@ -50,3 +46,27 @@ class RegistryDataInterface(object):
|
|||
Returns the matching LegacyImages under the matching repository, if any. If none,
|
||||
returns None.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def create_manifest_label(self, manifest, key, value, source_type_name, media_type_name=None):
|
||||
""" Creates a label on the manifest with the given key and value.
|
||||
|
||||
Can raise InvalidLabelKeyException or InvalidMediaTypeException depending
|
||||
on the validation errors.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def list_manifest_labels(self, manifest, key_prefix=None):
|
||||
""" Returns all labels found on the manifest. If specified, the key_prefix will filter the
|
||||
labels returned to those keys that start with the given prefix.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def get_manifest_label(self, manifest, label_uuid):
|
||||
""" Returns the label with the specified UUID on the manifest or None if none. """
|
||||
|
||||
@abstractmethod
|
||||
def delete_manifest_label(self, manifest, label_uuid):
|
||||
""" Delete the label with the specified UUID on the manifest. Returns the label deleted
|
||||
or None if none.
|
||||
"""
|
||||
|
|
|
@ -43,28 +43,28 @@ class PreOCIModel(RegistryDataInterface):
|
|||
|
||||
return Manifest.for_tag_manifest(tag_manifest)
|
||||
|
||||
def lookup_manifest_by_digest(self, repository_ref, manifest_digest, allow_dead=False):
|
||||
def lookup_manifest_by_digest(self, repository_ref, manifest_digest, allow_dead=False,
|
||||
include_legacy_image=False):
|
||||
""" Looks up the manifest with the given digest under the given repository and returns it
|
||||
or None if none. """
|
||||
repo = model.repository.lookup_repository(repository_ref._db_id)
|
||||
if repo is None:
|
||||
return None
|
||||
|
||||
tag_manifest = model.tag.load_manifest_by_digest(repo.namespace_user.username,
|
||||
repo.name,
|
||||
manifest_digest, allow_dead=allow_dead)
|
||||
return Manifest.for_tag_manifest(tag_manifest)
|
||||
|
||||
def create_manifest_label(self, manifest, key, value, source_type_name, media_type_name=None):
|
||||
""" Creates a label on the manifest with the given key and value. """
|
||||
try:
|
||||
tag_manifest = database.TagManifest.get(id=manifest._db_id)
|
||||
except database.TagManifest.DoesNotExist:
|
||||
tag_manifest = model.tag.load_manifest_by_digest(repo.namespace_user.username,
|
||||
repo.name,
|
||||
manifest_digest,
|
||||
allow_dead=allow_dead)
|
||||
except model.tag.InvalidManifestException:
|
||||
return None
|
||||
|
||||
label = model.label.create_manifest_label(tag_manifest, key, value, source_type_name,
|
||||
media_type_name)
|
||||
return Label.for_label(label)
|
||||
legacy_image = None
|
||||
if include_legacy_image:
|
||||
legacy_image = self.get_legacy_image(repository_ref, tag_manifest.tag.image.docker_image_id,
|
||||
include_parents=True)
|
||||
|
||||
return Manifest.for_tag_manifest(tag_manifest, legacy_image)
|
||||
|
||||
def get_legacy_images(self, repository_ref):
|
||||
"""
|
||||
|
@ -105,5 +105,32 @@ class PreOCIModel(RegistryDataInterface):
|
|||
|
||||
return LegacyImage.for_image(image, images_map=parent_images_map)
|
||||
|
||||
def create_manifest_label(self, manifest, key, value, source_type_name, media_type_name=None):
|
||||
""" Creates a label on the manifest with the given key and value. """
|
||||
try:
|
||||
tag_manifest = database.TagManifest.get(id=manifest._db_id)
|
||||
except database.TagManifest.DoesNotExist:
|
||||
return None
|
||||
|
||||
label = model.label.create_manifest_label(tag_manifest, key, value, source_type_name,
|
||||
media_type_name)
|
||||
return Label.for_label(label)
|
||||
|
||||
def list_manifest_labels(self, manifest, key_prefix=None):
|
||||
""" Returns all labels found on the manifest. If specified, the key_prefix will filter the
|
||||
labels returned to those keys that start with the given prefix.
|
||||
"""
|
||||
labels = model.label.list_manifest_labels(manifest._db_id, prefix_filter=key_prefix)
|
||||
return [Label.for_label(l) for l in labels]
|
||||
|
||||
def get_manifest_label(self, manifest, label_uuid):
|
||||
""" Returns the label with the specified UUID on the manifest or None if none. """
|
||||
return Label.for_label(model.label.get_manifest_label(label_uuid, manifest._db_id))
|
||||
|
||||
def delete_manifest_label(self, manifest, label_uuid):
|
||||
""" Delete the label with the specified UUID on the manifest. Returns the label deleted
|
||||
or None if none.
|
||||
"""
|
||||
return Label.for_label(model.label.delete_manifest_label(label_uuid, manifest._db_id))
|
||||
|
||||
pre_oci_model = PreOCIModel()
|
||||
|
|
|
@ -28,7 +28,7 @@ def test_find_matching_tag(names, expected, pre_oci_model):
|
|||
|
||||
|
||||
@pytest.mark.parametrize('repo_namespace, repo_name, expected', [
|
||||
('devtable', 'simple', {'latest'}),
|
||||
('devtable', 'simple', {'latest', 'prod'}),
|
||||
('buynlarge', 'orgrepo', {'latest', 'prod'}),
|
||||
])
|
||||
def test_get_most_recent_tag(repo_namespace, repo_name, expected, pre_oci_model):
|
||||
|
@ -63,18 +63,18 @@ def test_lookup_manifests(repo_namespace, repo_name, pre_oci_model):
|
|||
repository_ref = RepositoryReference.for_repo_obj(repo)
|
||||
found_tag = pre_oci_model.find_matching_tag(repository_ref, ['latest'])
|
||||
found_manifest = pre_oci_model.get_manifest_for_tag(found_tag)
|
||||
found = pre_oci_model.lookup_manifest_by_digest(repository_ref, found_manifest.digest)
|
||||
found = pre_oci_model.lookup_manifest_by_digest(repository_ref, found_manifest.digest,
|
||||
include_legacy_image=True)
|
||||
assert found._db_id == found_manifest._db_id
|
||||
assert found.digest == found_manifest.digest
|
||||
assert found.legacy_image
|
||||
|
||||
|
||||
def test_create_manifest_label(pre_oci_model):
|
||||
def test_lookup_unknown_manifest(pre_oci_model):
|
||||
repo = model.repository.get_repository('devtable', 'simple')
|
||||
repository_ref = RepositoryReference.for_repo_obj(repo)
|
||||
found_tag = pre_oci_model.find_matching_tag(repository_ref, ['latest'])
|
||||
found_manifest = pre_oci_model.get_manifest_for_tag(found_tag)
|
||||
|
||||
pre_oci_model.create_manifest_label(found_manifest, 'foo', 'bar', 'internal')
|
||||
found = pre_oci_model.lookup_manifest_by_digest(repository_ref, 'sha256:deadbeef')
|
||||
assert found is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize('repo_namespace, repo_name', [
|
||||
|
@ -116,3 +116,32 @@ def test_legacy_images(repo_namespace, repo_name, pre_oci_model):
|
|||
|
||||
unknown = pre_oci_model.get_legacy_image(repository_ref, 'unknown', include_parents=True)
|
||||
assert unknown is None
|
||||
|
||||
|
||||
def test_manifest_labels(pre_oci_model):
|
||||
repo = model.repository.get_repository('devtable', 'simple')
|
||||
repository_ref = RepositoryReference.for_repo_obj(repo)
|
||||
found_tag = pre_oci_model.find_matching_tag(repository_ref, ['latest'])
|
||||
found_manifest = pre_oci_model.get_manifest_for_tag(found_tag)
|
||||
|
||||
# Create a new label.
|
||||
created = pre_oci_model.create_manifest_label(found_manifest, 'foo', 'bar', 'api')
|
||||
assert created.key == 'foo'
|
||||
assert created.value == 'bar'
|
||||
assert created.source_type_name == 'api'
|
||||
assert created.media_type_name == 'text/plain'
|
||||
|
||||
# Ensure we can look it up.
|
||||
assert pre_oci_model.get_manifest_label(found_manifest, created.uuid) == created
|
||||
|
||||
# Ensure it is in our list of labels.
|
||||
assert created in pre_oci_model.list_manifest_labels(found_manifest)
|
||||
assert created in pre_oci_model.list_manifest_labels(found_manifest, key_prefix='fo')
|
||||
|
||||
# Ensure it is *not* in our filtered list.
|
||||
assert created not in pre_oci_model.list_manifest_labels(found_manifest, key_prefix='ba')
|
||||
|
||||
# Delete the label and ensure it is gone.
|
||||
assert pre_oci_model.delete_manifest_label(found_manifest, created.uuid)
|
||||
assert pre_oci_model.get_manifest_label(found_manifest, created.uuid) is None
|
||||
assert created not in pre_oci_model.list_manifest_labels(found_manifest)
|
||||
|
|
Reference in a new issue