Merge pull request #3369 from quay/fix-broken-manifest-builder

Fix broken manifest builder
This commit is contained in:
Joseph Schorr 2019-02-15 21:46:02 -05:00 committed by GitHub
commit f2a351183a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 9 deletions

View file

@ -7,13 +7,15 @@ from collections import namedtuple
from flask import session from flask import session
from data import model from data import model
from data.database import db_transaction from data.database import db_transaction, ImageStorage
from data.registry_model import registry_model from data.registry_model import registry_model
from image.docker.schema2 import EMPTY_LAYER_BLOB_DIGEST
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
ManifestLayer = namedtuple('ManifestLayer', ['layer_id', 'v1_metadata_string', 'db_id']) ManifestLayer = namedtuple('ManifestLayer', ['layer_id', 'v1_metadata_string', 'db_id'])
_BuilderState = namedtuple('_BuilderState', ['builder_id', 'images', 'tags', 'checksums']) _BuilderState = namedtuple('_BuilderState', ['builder_id', 'images', 'tags', 'checksums',
'temp_storages'])
_SESSION_KEY = '__manifestbuilder' _SESSION_KEY = '__manifestbuilder'
@ -23,7 +25,7 @@ def create_manifest_builder(repository_ref, storage):
and returns it. Returns None if the builder could not be constructed. and returns it. Returns None if the builder could not be constructed.
""" """
builder_id = str(uuid.uuid4()) builder_id = str(uuid.uuid4())
builder = _ManifestBuilder(repository_ref, _BuilderState(builder_id, {}, {}, {}), storage) builder = _ManifestBuilder(repository_ref, _BuilderState(builder_id, {}, {}, {}, []), storage)
builder._save_to_session() builder._save_to_session()
return builder return builder
@ -111,10 +113,6 @@ class _ManifestBuilder(object):
location_name) location_name)
model.tag.create_temporary_hidden_tag(repository, created, temp_tag_expiration) model.tag.create_temporary_hidden_tag(repository, created, temp_tag_expiration)
# Mark the image as uploading.
created.storage.uploading = True
created.storage.save()
# Save its V1 metadata. # Save its V1 metadata.
command_list = v1_metadata.get('container_config', {}).get('Cmd', None) command_list = v1_metadata.get('container_config', {}).get('Cmd', None)
command = json.dumps(command_list) if command_list else None command = json.dumps(command_list) if command_list else None
@ -155,7 +153,9 @@ class _ManifestBuilder(object):
existing_storage = repo_image.storage existing_storage = repo_image.storage
repo_image.storage = blob._db_id repo_image.storage = blob._db_id
repo_image.save() repo_image.save()
existing_storage.delete_instance(recursive=True)
if existing_storage.uploading:
self._builder_state.temp_storages.append(existing_storage.id)
self._builder_state.checksums[layer.layer_id] = computed_checksums self._builder_state.checksums[layer.layer_id] = computed_checksums
self._save_to_session() self._save_to_session()
@ -198,6 +198,15 @@ class _ManifestBuilder(object):
and it is expected manifest builders will eventually time out if unused for an and it is expected manifest builders will eventually time out if unused for an
extended period of time. extended period of time.
""" """
temp_storages = self._builder_state.temp_storages
for storage_id in temp_storages:
try:
storage = ImageStorage.get(id=storage_id)
if storage.uploading and storage.content_checksum != EMPTY_LAYER_BLOB_DIGEST:
storage.delete_instance()
except ImageStorage.DoesNotExist:
pass
session.pop(_SESSION_KEY, None) session.pop(_SESSION_KEY, None)
def _save_to_session(self): def _save_to_session(self):

View file

@ -434,12 +434,24 @@ class SharedModel:
# Add the leaf layer # Add the leaf layer
builder.add_layer(legacy_image_row.storage.content_checksum, legacy_image_row.v1_json_metadata) builder.add_layer(legacy_image_row.storage.content_checksum, legacy_image_row.v1_json_metadata)
if legacy_image_row.storage.uploading:
logger.error('Cannot add an uploading storage row: %s', legacy_image_row.storage.id)
return None
for parent_image in parents: for parent_image in parents:
if parent_image.storage.uploading:
logger.error('Cannot add an uploading storage row: %s', legacy_image_row.storage.id)
return None
builder.add_layer(parent_image.storage.content_checksum, parent_image.v1_json_metadata) builder.add_layer(parent_image.storage.content_checksum, parent_image.v1_json_metadata)
# Sign the manifest with our signing key. # Sign the manifest with our signing key.
try:
return builder.build(docker_v2_signing_key) return builder.build(docker_v2_signing_key)
except ManifestException as me:
logger.exception('Got exception when trying to build manifest for legacy image %s',
legacy_image_row)
return None
def _get_shared_storage(self, blob_digest): def _get_shared_storage(self, blob_digest):
""" Returns an ImageStorage row for the blob digest if it is a globally shared storage. """ """ Returns an ImageStorage row for the blob digest if it is a globally shared storage. """