diff --git a/endpoints/v2/manifest.py b/endpoints/v2/manifest.py index e22a7d423..df116a87d 100644 --- a/endpoints/v2/manifest.py +++ b/endpoints/v2/manifest.py @@ -185,13 +185,6 @@ class SignedManifestBuilder(object): _V1_COMPAT_KEY: v1_json_metadata, }) - def add_top_layer(self, layer_digest, v1_json_metadata): - self._fs_layer_digests.insert(0, { - _BLOB_SUM_KEY: layer_digest, - }) - self._history.insert(0, { - _V1_COMPAT_KEY: v1_json_metadata, - }) def build(self, json_web_key): """ Build the payload and sign it, returning a SignedManifest object. @@ -395,53 +388,33 @@ def _write_manifest(namespace, repo_name, manifest): # a storage with a content checksum different from the existing, then we need to rewrite # the Docker ID to ensure consistency. tag_name = manifest.tag - updated_manifest_builder = SignedManifestBuilder(namespace, repo_name, tag_name) - has_updated_manifest = False + has_rewritten_ids = False updated_id_map = {} for mdata in layers: digest_str = str(mdata.digest) v1_mdata = mdata.v1_metadata - updated_id_map[v1_mdata.docker_id] = v1_mdata.docker_id + working_docker_id = v1_mdata.docker_id # Ensure that all blobs exist. blob_storage = storage_map.get(digest_str) if blob_storage is None: raise BlobUnknown(detail={'digest': digest_str}) - if v1_mdata.docker_id in images_map: - # Ensure that the V1 image's storage matches the V2 blob. If not, we've found - # a data inconsistency and need to create a new layer ID for the V1 image. - v1_image = images_map[v1_mdata.docker_id] - if has_updated_manifest or v1_image.storage.content_checksum != digest_str: - new_synthetic_id = hashlib.sha256(mdata.v1_metadata_str + '@' + digest_str).hexdigest() - logger.debug('Got content mismatch for layer %s under repo %s/%s. New ID: %s', - v1_mdata.docker_id, namespace, repo_name, new_synthetic_id) + # Ensure that the V1 image's storage matches the V2 blob. If not, we've found + # a data inconsistency and need to create a new layer ID for the V1 image, and all images + # that follow it in the ancestry chain. + if ((v1_mdata.docker_id in images_map and + images_map[v1_mdata.docker_id].storage.content_checksum != digest_str) or + has_rewritten_ids): - updated_id_map[v1_mdata.docker_id] = new_synthetic_id - has_updated_manifest = True + working_docker_id = hashlib.sha256(mdata.v1_metadata_str + '@' + digest_str).hexdigest() + logger.debug('Rewriting docker_id %s/%s %s -> %s', namespace, repo_name, v1_mdata.docker_id, + working_docker_id) + has_rewritten_ids = True - # Update the manifest withn the new ID (if any). - v1_metadata_json = mdata.v1_metadata_str - if has_updated_manifest: - v1_metadata_json = _updated_v1_metadata(mdata.v1_metadata_str, updated_id_map) - - updated_manifest_builder.add_top_layer(digest_str, v1_metadata_json) - - # If the manifest was changed due to an updated layer ID, then create a new manifest - # based on the updated data. - if has_updated_manifest: - manifest = updated_manifest_builder.build(docker_v2_signing_key) - layers = list(manifest.layers) - - # Synthesize the V1 metadata for each layer. - for mdata in layers: - v1_mdata = mdata.v1_metadata - - # If the layer with the V1 id already exists, then nothing more to do. We've ensured - # it points to the correct content SHA above. - if v1_mdata.docker_id in images_map: - continue + # Store the new docker id in the map + updated_id_map[v1_mdata.docker_id] = working_docker_id # Lookup the parent image for the layer, if any. parent_image = None @@ -454,9 +427,14 @@ def _write_manifest(namespace, repo_name, manifest): # Synthesize and store the v1 metadata in the db. digest_str = str(mdata.digest) blob_storage = storage_map[digest_str] - image = model.image.synthesize_v1_image(repo, blob_storage, v1_mdata.docker_id, + + v1_metadata_json = mdata.v1_metadata_str + if has_rewritten_ids: + v1_metadata_json = _updated_v1_metadata(mdata.v1_metadata_str, updated_id_map) + + image = model.image.synthesize_v1_image(repo, blob_storage, working_docker_id, v1_mdata.created, v1_mdata.comment, v1_mdata.command, - mdata.v1_metadata_str, parent_image) + v1_metadata_json, parent_image) images_map[v1_mdata.docker_id] = image @@ -466,9 +444,9 @@ def _write_manifest(namespace, repo_name, manifest): # Store the manifest pointing to the tag. manifest_digest = manifest.digest - leaf_layer = layers[-1] - model.tag.store_tag_manifest(namespace, repo_name, tag_name, leaf_layer.v1_metadata.docker_id, - manifest_digest, manifest.bytes) + leaf_layer_id = images_map[layers[-1].v1_metadata.docker_id].docker_image_id + model.tag.store_tag_manifest(namespace, repo_name, tag_name, leaf_layer_id, manifest_digest, + manifest.bytes) # Spawn the repo_push event. event_data = { diff --git a/test/registry_tests.py b/test/registry_tests.py index 8f4f96d49..d2507405a 100644 --- a/test/registry_tests.py +++ b/test/registry_tests.py @@ -678,7 +678,7 @@ class V2RegistryPullMixin(V2RegistryMixin): found_v1_layers.add(v1_history['id']) for image in images: - self.assertEquals(not munge_shas, image['id'] in found_v1_layers) + self.assertIn(image['id'], found_v1_layers) return blobs