def get_image_with_storage_and_parent_base(): Parent = Image.alias() ParentImageStorage = ImageStorage.alias() return ( Image.select(Image, ImageStorage, Parent, ParentImageStorage) .join(ImageStorage) .switch(Image) .join(Parent, JOIN.LEFT_OUTER, on=(Image.parent == Parent.id)) .join(ParentImageStorage, JOIN.LEFT_OUTER, on=(ParentImageStorage.id == Parent.storage)) )
def get_tags_images_eligible_for_scan(clair_version): Parent = Image.alias() ParentImageStorage = ImageStorage.alias() return _tag_alive( RepositoryTag.select(Image, ImageStorage, Parent, ParentImageStorage, RepositoryTag).join( Image, on=(RepositoryTag.image == Image.id)). join(ImageStorage, on=(Image.storage == ImageStorage.id)).switch(Image).join( Parent, JOIN.LEFT_OUTER, on=(Image.parent == Parent.id)).join( ParentImageStorage, JOIN.LEFT_OUTER, on=(ParentImageStorage.id == Parent.storage)).where( RepositoryTag.hidden == False).where( Image.security_indexed_engine < clair_version))
def get_matching_tags_for_images(image_pairs, filter_images=None, filter_tags=None, selections=None): """ Returns all tags that contain the images with the given docker_image_id and storage_uuid, as specified as an iterable of pairs. """ if not image_pairs: return [] image_pairs_set = set(image_pairs) # Find all possible matching image+storages. images = [] while image_pairs: image_pairs_slice = image_pairs[:_MAX_IMAGE_LOOKUP_COUNT] ids = [pair[0] for pair in image_pairs_slice] uuids = [pair[1] for pair in image_pairs_slice] images_query = (Image.select( Image.id, Image.docker_image_id, Image.ancestors, ImageStorage.uuid).join(ImageStorage).where( Image.docker_image_id << ids, ImageStorage.uuid << uuids).switch(Image)) if filter_images is not None: images_query = filter_images(images_query) images.extend(list(images_query)) image_pairs = image_pairs[_MAX_IMAGE_LOOKUP_COUNT:] # Filter down to those images actually in the pairs set and build the set of queries to run. individual_image_queries = [] for img in images: # Make sure the image found is in the set of those requested, and that we haven't already # processed it. We need this check because the query above checks for images with matching # IDs OR storage UUIDs, rather than the expected ID+UUID pair. We do this for efficiency # reasons, and it is highly unlikely we'll find an image with a mismatch, but we need this # check to be absolutely sure. pair = (img.docker_image_id, img.storage.uuid) if pair not in image_pairs_set: continue # Remove the pair so we don't try it again. image_pairs_set.remove(pair) ancestors_str = "%s%s/%%" % (img.ancestors, img.id) query = Image.select( Image.id).where((Image.id == img.id) | (Image.ancestors**ancestors_str)) individual_image_queries.append(query) if not individual_image_queries: return [] # Shard based on the max subquery count. This is used to prevent going over the DB's max query # size, as well as to prevent the DB from locking up on a massive query. sharded_queries = [] while individual_image_queries: shard = individual_image_queries[:_MAX_SUB_QUERIES] sharded_queries.append(_basequery.reduce_as_tree(shard)) individual_image_queries = individual_image_queries[_MAX_SUB_QUERIES:] # Collect IDs of the tags found for each query. tags = {} for query in sharded_queries: ImageAlias = Image.alias() tag_query = _tag_alive( RepositoryTag.select( *(selections or [])).distinct().join(ImageAlias).where( RepositoryTag.hidden == False).where( ImageAlias.id << query).switch(RepositoryTag)) if filter_tags is not None: tag_query = filter_tags(tag_query) for tag in tag_query: tags[tag.id] = tag return tags.values()