def find_or_create_derived_storage(source_image, transformation_name, preferred_location, varying_metadata=None): existing = find_derived_storage_for_image(source_image, transformation_name, varying_metadata) if existing is not None: return existing uniqueness_hash = _get_uniqueness_hash(varying_metadata) trans = ImageStorageTransformation.get(name=transformation_name) new_storage = storage.create_v1_storage(preferred_location) try: derived = DerivedStorageForImage.create( source_image=source_image, derivative=new_storage, transformation=trans, uniqueness_hash=uniqueness_hash, ) except IntegrityError: # Storage was created while this method executed. Just return the existing. ImageStoragePlacement.delete().where( ImageStoragePlacement.storage == new_storage).execute() new_storage.delete_instance() return find_derived_storage_for_image(source_image, transformation_name, varying_metadata) return derived
def find_create_or_link_image( docker_image_id, repo_obj, username, translations, preferred_location ): # First check for the image existing in the repository. If found, we simply return it. repo_image = get_repo_image(repo_obj.namespace_user.username, repo_obj.name, docker_image_id) if repo_image: return repo_image # We next check to see if there is an existing storage the new image can link to. existing_image_query = ( Image.select(Image, ImageStorage) .distinct() .join(ImageStorage) .switch(Image) .join(Repository) .join(RepositoryPermission, JOIN.LEFT_OUTER) .switch(Repository) .join(Namespace, on=(Repository.namespace_user == Namespace.id)) .where(Image.docker_image_id == docker_image_id) ) existing_image_query = _basequery.filter_to_repos_for_user( existing_image_query, _namespace_id_for_username(username) ) # If there is an existing image, we try to translate its ancestry and copy its storage. new_image = None try: logger.debug("Looking up existing image for ID: %s", docker_image_id) existing_image = existing_image_query.get() logger.debug("Existing image %s found for ID: %s", existing_image.id, docker_image_id) new_image = _find_or_link_image( existing_image, repo_obj, username, translations, preferred_location ) if new_image: return new_image except Image.DoesNotExist: logger.debug("No existing image found for ID: %s", docker_image_id) # Otherwise, create a new storage directly. with db_transaction(): # Final check for an existing image, under the transaction. repo_image = get_repo_image( repo_obj.namespace_user.username, repo_obj.name, docker_image_id ) if repo_image: return repo_image logger.debug("Creating new storage for docker id: %s", docker_image_id) new_storage = storage.create_v1_storage(preferred_location) return Image.create( docker_image_id=docker_image_id, repository=repo_obj, storage=new_storage, ancestors="/" )