Merge pull request #3332 from quay/joseph.schorr/QUAY-1245/retarget-schema1-manifest

Add support for retargeting a tag to all schema 1 manifests
This commit is contained in:
Joseph Schorr 2019-01-16 15:06:08 -05:00 committed by GitHub
commit f03abfef12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 0 deletions

View file

@ -14,6 +14,7 @@ from data.registry_model.datatypes import (Tag, Manifest, LegacyImage, Label, Se
from data.registry_model.shared import SharedModel
from data.registry_model.label_handlers import apply_label_to_manifest
from image.docker import ManifestException
from image.docker.schema1 import DOCKER_SCHEMA1_CONTENT_TYPES
from image.docker.schema2 import DOCKER_SCHEMA2_MANIFESTLIST_CONTENT_TYPE
@ -313,6 +314,28 @@ class OCIModel(SharedModel, RegistryDataInterface):
return None
manifest_id = created.manifest.id
else:
# If the manifest is a schema 1 manifest and its tag name does not match that
# specified, then we need to create a new manifest, but with that tag name.
if manifest_or_legacy_image.media_type in DOCKER_SCHEMA1_CONTENT_TYPES:
try:
parsed = manifest_or_legacy_image.get_parsed_manifest()
except ManifestException:
logger.exception('Could not parse manifest `%s` in retarget_tag',
manifest_or_legacy_image._db_id)
return None
if parsed.tag != tag_name:
logger.debug('Rewriting manifest `%s` for tag named `%s`',
manifest_or_legacy_image._db_id, tag_name)
repository_id = repository_ref._db_id
updated = parsed.with_tag_name(tag_name)
created = oci.manifest.get_or_create_manifest(repository_id, updated, storage)
if created is None:
return None
manifest_id = created.manifest.id
tag = oci.tag.retarget_tag(tag_name, manifest_id, is_reversion=is_reversion)
legacy_image = LegacyImage.for_image(oci.shared.get_legacy_image_for_manifest(manifest_id))

View file

@ -342,6 +342,30 @@ def test_retarget_tag_history(use_manifest, registry_model):
assert len(new_history) == len(history) + 1
def test_retarget_tag_schema1(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)
existing_parsed = manifest.get_parsed_manifest()
# Retarget a new tag to the manifest.
updated_tag = oci_model.retarget_tag(repository_ref, 'somenewtag', manifest, storage)
assert updated_tag
assert updated_tag.name == 'somenewtag'
updated_manifest = oci_model.get_manifest_for_tag(updated_tag)
parsed = updated_manifest.get_parsed_manifest()
assert parsed.namespace == 'devtable'
assert parsed.repo_name == 'simple'
assert parsed.tag == 'somenewtag'
assert parsed.layers == existing_parsed.layers
# Ensure the tag has changed targets.
assert oci_model.get_repo_tag(repository_ref, 'somenewtag') == updated_tag
def test_change_repository_tag_expiration(registry_model):
repository_ref = registry_model.lookup_repository('devtable', 'simple')
tag = registry_model.get_repo_tag(repository_ref, 'latest')

View file

@ -356,6 +356,15 @@ class DockerSchema1Manifest(ManifestInterface):
return builder.build()
def with_tag_name(self, tag_name, json_web_key=None):
""" Returns a copy of this manifest, with the tag changed to the given tag name. """
builder = DockerSchema1ManifestBuilder(self._namespace, self._repo_name, tag_name,
self._architecture)
for layer in reversed(self.layers):
builder.add_layer(str(layer.digest), layer.raw_v1_metadata)
return builder.build(json_web_key)
def _generate_layers(self):
"""
Returns a generator of objects that have the blobSum and v1Compatibility keys in them,