Merge pull request #3401 from quay/fix-oci-tags-ordering

Fix ordering of tags in the OCI model
This commit is contained in:
Joseph Schorr 2019-03-07 13:58:26 -05:00 committed by GitHub
commit 23d8ecc3cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 51 additions and 6 deletions

View file

@ -44,7 +44,7 @@ def get_tag(repository_id, tag_name):
return None return None
def list_alive_tags(repository_id, start_pagination_id=None, limit=None): def list_alive_tags(repository_id, start_pagination_id=None, limit=None, sort_tags=False):
""" Returns a list of all the tags alive in the specified repository, with optional limits. """ Returns a list of all the tags alive in the specified repository, with optional limits.
Tag's returned are joined with their manifest. Tag's returned are joined with their manifest.
""" """
@ -54,11 +54,15 @@ def list_alive_tags(repository_id, start_pagination_id=None, limit=None):
.where(Tag.repository == repository_id)) .where(Tag.repository == repository_id))
if start_pagination_id is not None: if start_pagination_id is not None:
assert sort_tags
query = query.where(Tag.id >= start_pagination_id) query = query.where(Tag.id >= start_pagination_id)
if limit is not None: if limit is not None:
query = query.limit(limit) query = query.limit(limit)
if sort_tags:
query = query.order_by(Tag.id)
return filter_to_visible_tags(filter_to_alive_tags(query)) return filter_to_visible_tags(filter_to_alive_tags(query))

View file

@ -114,7 +114,8 @@ class RegistryDataInterface(object):
@abstractmethod @abstractmethod
def list_repository_tags(self, repository_ref, include_legacy_images=False, def list_repository_tags(self, repository_ref, include_legacy_images=False,
start_pagination_id=None, start_pagination_id=None,
limit=None): limit=None,
sort_tags=False):
""" """
Returns a list of all the active tags in the repository. Note that this can be a *heavy* Returns a list of all the active tags in the repository. Note that this can be a *heavy*
operation on repositories with a lot of tags, and should be avoided for more targetted operation on repositories with a lot of tags, and should be avoided for more targetted

View file

@ -201,13 +201,18 @@ class OCIModel(SharedModel, RegistryDataInterface):
def list_repository_tags(self, repository_ref, include_legacy_images=False, def list_repository_tags(self, repository_ref, include_legacy_images=False,
start_pagination_id=None, start_pagination_id=None,
limit=None): limit=None,
sort_tags=False):
""" """
Returns a list of all the active tags in the repository. Note that this can be a *heavy* Returns a list of all the active tags in the repository. Note that this can be a *heavy*
operation on repositories with a lot of tags, and should be avoided for more targetted operation on repositories with a lot of tags, and should be avoided for more targetted
operations wherever possible. operations wherever possible.
""" """
tags = list(oci.tag.list_alive_tags(repository_ref._db_id, start_pagination_id, limit)) if start_pagination_id:
assert sort_tags
tags = list(oci.tag.list_alive_tags(repository_ref._db_id, start_pagination_id, limit,
sort_tags=sort_tags))
legacy_images_map = {} legacy_images_map = {}
if include_legacy_images: if include_legacy_images:
legacy_images_map = oci.tag.get_legacy_images_for_tags(tags) legacy_images_map = oci.tag.get_legacy_images_for_tags(tags)

View file

@ -265,7 +265,8 @@ class PreOCIModel(SharedModel, RegistryDataInterface):
def list_repository_tags(self, repository_ref, include_legacy_images=False, def list_repository_tags(self, repository_ref, include_legacy_images=False,
start_pagination_id=None, start_pagination_id=None,
limit=None): limit=None,
sort_tags=False):
""" """
Returns a list of all the active tags in the repository. Note that this can be a *heavy* Returns a list of all the active tags in the repository. Note that this can be a *heavy*
operation on repositories with a lot of tags, and should be avoided for more targetted operation on repositories with a lot of tags, and should be avoided for more targetted

View file

@ -936,3 +936,37 @@ def test_unicode_emoji(registry_model):
assert found.digest == manifest.digest assert found.digest == manifest.digest
assert found.internal_manifest_bytes.as_encoded_str() == manifest.bytes.as_encoded_str() assert found.internal_manifest_bytes.as_encoded_str() == manifest.bytes.as_encoded_str()
assert found.get_parsed_manifest().digest == manifest.digest assert found.get_parsed_manifest().digest == manifest.digest
def test_list_repository_tags(oci_model):
repository_ref = oci_model.lookup_repository('devtable', 'simple')
latest_tag = oci_model.get_repo_tag(repository_ref, 'latest')
manifest = oci_model.get_manifest_for_tag(latest_tag)
tag_count = 500
# Create a bunch of tags.
tags_expected = set()
for index in range(0, tag_count):
tags_expected.add('somenewtag%s' % index)
oci_model.retarget_tag(repository_ref, 'somenewtag%s' % index, manifest, storage)
# List the tags.
tags_found = set()
tag_id = None
while True:
tags = oci_model.list_repository_tags(repository_ref, start_pagination_id=tag_id,
limit=11, sort_tags=True)
assert len(tags) <= 11
for tag in tags[0:10]:
assert tag.name not in tags_found
if tag.name in tags_expected:
tags_expected.remove(tag.name)
if len(tags) < 11:
break
tag_id = tags[10].id
# Make sure we've found all the tags.
assert not tags_expected

View file

@ -21,7 +21,7 @@ def list_all_tags(namespace_name, repo_name, start_id, limit, pagination_callbac
# NOTE: We add 1 to the limit because that's how pagination_callback knows if there are # NOTE: We add 1 to the limit because that's how pagination_callback knows if there are
# additional tags. # additional tags.
tags = registry_model.list_repository_tags(repository_ref, start_pagination_id=start_id, tags = registry_model.list_repository_tags(repository_ref, start_pagination_id=start_id,
limit=limit + 1) limit=limit + 1, sort_tags=True)
response = jsonify({ response = jsonify({
'name': '{0}/{1}'.format(namespace_name, repo_name), 'name': '{0}/{1}'.format(namespace_name, repo_name),
'tags': [tag.name for tag in tags][0:limit], 'tags': [tag.name for tag in tags][0:limit],