Esempio n. 1
0
File: tag.py Progetto: zhill/quay
def list_active_repo_tags(repo,
                          start_id=None,
                          limit=None,
                          include_images=True):
    """ Returns all of the active, non-hidden tags in a repository, joined to they images
      and (if present), their manifest.
  """
    if include_images:
        query = _tag_alive(
            RepositoryTag.select(
                RepositoryTag, Image, ImageStorage,
                TagManifest.digest).join(Image).join(ImageStorage).where(
                    RepositoryTag.repository == repo,
                    RepositoryTag.hidden == False).switch(RepositoryTag).join(
                        TagManifest,
                        JOIN.LEFT_OUTER).order_by(RepositoryTag.id))
    else:
        query = _tag_alive(
            RepositoryTag.select(RepositoryTag).where(
                RepositoryTag.repository == repo,
                RepositoryTag.hidden == False).order_by(RepositoryTag.id))

    if start_id is not None:
        query = query.where(RepositoryTag.id >= start_id)

    if limit is not None:
        query = query.limit(limit)

    return query
Esempio n. 2
0
def find_repository_with_garbage(limit_to_gc_policy_s):
    expiration_timestamp = get_epoch_timestamp() - limit_to_gc_policy_s

    try:
        candidates = (RepositoryTag.select(
            RepositoryTag.repository).join(Repository).join(
                Namespace,
                on=(Repository.namespace_user == Namespace.id)).where(
                    ~(RepositoryTag.lifetime_end_ts >> None),
                    (RepositoryTag.lifetime_end_ts <= expiration_timestamp),
                    (Namespace.removed_tag_expiration_s
                     == limit_to_gc_policy_s),
                ).limit(500).distinct().alias("candidates"))

        found = (RepositoryTag.select(
            candidates.c.repository_id).from_(candidates).order_by(
                db_random_func()).get())

        if found is None:
            return

        return Repository.get(Repository.id == found.repository_id)
    except RepositoryTag.DoesNotExist:
        return None
    except Repository.DoesNotExist:
        return None
Esempio n. 3
0
File: tag.py Progetto: zhill/quay
def get_matching_tags(docker_image_id, storage_uuid, *args):
    """ Returns a query pointing to all tags that contain the image with the
      given docker_image_id and storage_uuid. """
    image_row = image.get_image_with_storage(docker_image_id, storage_uuid)
    if image_row is None:
        return RepositoryTag.select().where(
            RepositoryTag.id < 0)  # Empty query.

    ancestors_str = "%s%s/%%" % (image_row.ancestors, image_row.id)
    return _tag_alive(
        RepositoryTag.select(
            *args).distinct().join(Image).join(ImageStorage).where(
                RepositoryTag.hidden == False).where(
                    (Image.id == image_row.id)
                    | (Image.ancestors**ancestors_str)))
Esempio n. 4
0
    def _candidates_to_backfill(self):
        def missing_tmt_query():
            return (
                self._filter(RepositoryTag.select())
                .join(TagToRepositoryTag, JOIN.LEFT_OUTER)
                .where(TagToRepositoryTag.id >> None, RepositoryTag.hidden == False)
            )

        min_id = self._filter(RepositoryTag.select(fn.Min(RepositoryTag.id))).scalar()
        max_id = self._filter(RepositoryTag.select(fn.Max(RepositoryTag.id))).scalar()

        logger.info("Found candidate range %s-%s", min_id, max_id)

        iterator = yield_random_entries(missing_tmt_query, RepositoryTag.id, 1000, max_id, min_id,)

        return iterator
Esempio n. 5
0
def _delete_temp_links(repo):
    """ Deletes any temp links to blobs. """
    for hidden in list(
        RepositoryTag.select().where(RepositoryTag.hidden == True, RepositoryTag.repository == repo)
    ):
        hidden.delete_instance()
        hidden.image.delete_instance()
Esempio n. 6
0
def test_get_matching_tag_ids_images_filtered(initialized_db):
    def filter_query(query):
        return query.join(Repository).where(Repository.name == "simple")

    filtered_images = filter_query(
        Image.select(Image, ImageStorage)
        .join(RepositoryTag)
        .switch(Image)
        .join(ImageStorage)
        .switch(Image)
    )

    expected_tags_query = _tag_alive(filter_query(RepositoryTag.select()))

    pairs = []
    for image in filtered_images:
        pairs.append((image.docker_image_id, image.storage.uuid))

    matching_tags = get_matching_tags_for_images(
        pairs, filter_images=filter_query, filter_tags=filter_query
    )

    expected_tag_ids = set([tag.id for tag in expected_tags_query])
    matching_tags_ids = set([tag.id for tag in matching_tags])

    # Ensure every alive tag was found.
    assert matching_tags_ids == expected_tag_ids
Esempio n. 7
0
def get_min_id_for_sec_scan(version):
    """
    Gets the minimum id for a security scanning.
    """
    return _tag_alive(
        RepositoryTag.select(fn.Min(RepositoryTag.id)).join(Image).where(
            Image.security_indexed_engine < version)).scalar()
Esempio n. 8
0
def _get_expected_tags(image):
    expected_query = (
        RepositoryTag.select()
        .join(Image)
        .where(RepositoryTag.hidden == False)
        .where((Image.id == image.id) | (Image.ancestors ** ("%%/%s/%%" % image.id)))
    )
    return set([tag.id for tag in _tag_alive(expected_query)])
def upgrade(tables, tester, progress_reporter):
    if not app.config.get("SETUP_COMPLETE", False):
        return

    start_id = 0
    end_id = 1000
    size = 1000

    max_id = RepositoryTag.select(fn.Max(RepositoryTag.id)).scalar()
    if max_id is None:
        return

    logger.info("Found maximum ID %s" % max_id)

    while True:
        if start_id > max_id:
            break

        logger.info("Checking tag range %s - %s", start_id, end_id)
        r = list(
            RepositoryTag.select()
            .join(Repository)
            .switch(RepositoryTag)
            .join(TagToRepositoryTag, JOIN.LEFT_OUTER)
            .where(TagToRepositoryTag.id >> None)
            .where(
                RepositoryTag.hidden == False,
                RepositoryTag.id >= start_id,
                RepositoryTag.id < end_id,
            )
        )

        if len(r) < 1000 and size < 100000:
            size *= 2

        start_id = end_id
        end_id = start_id + size

        if not len(r):
            continue

        logger.info("Found %s tags to backfill", len(r))
        for index, t in enumerate(r):
            logger.info("Backfilling tag %s of %s", index, len(r))
            backfill_tag(t)
Esempio n. 10
0
def purge_repository(repo, force=False):
    """
    Completely delete all traces of the repository.

    Will return True upon complete success, and False upon partial or total failure. Garbage
    collection is incremental and repeatable, so this return value does not need to be checked or
    responded to.
    """
    assert repo.state == RepositoryState.MARKED_FOR_DELETION or force

    # Delete the repository of all Appr-referenced entries.
    # Note that new-model Tag's must be deleted in *two* passes, as they can reference parent tags,
    # and MySQL is... particular... about such relationships when deleting.
    if repo.kind.name == "application":
        ApprTag.delete().where(ApprTag.repository == repo,
                               ~(ApprTag.linked_tag >> None)).execute()
        ApprTag.delete().where(ApprTag.repository == repo).execute()
    else:
        # GC to remove the images and storage.
        _purge_repository_contents(repo)

    # Ensure there are no additional tags, manifests, images or blobs in the repository.
    assert ApprTag.select().where(ApprTag.repository == repo).count() == 0
    assert Tag.select().where(Tag.repository == repo).count() == 0
    assert RepositoryTag.select().where(
        RepositoryTag.repository == repo).count() == 0
    assert Manifest.select().where(Manifest.repository == repo).count() == 0
    assert ManifestBlob.select().where(
        ManifestBlob.repository == repo).count() == 0
    assert Image.select().where(Image.repository == repo).count() == 0

    # Delete any repository build triggers, builds, and any other large-ish reference tables for
    # the repository.
    _chunk_delete_all(repo, RepositoryPermission, force=force)
    _chunk_delete_all(repo, RepositoryBuild, force=force)
    _chunk_delete_all(repo, RepositoryBuildTrigger, force=force)
    _chunk_delete_all(repo, RepositoryActionCount, force=force)
    _chunk_delete_all(repo, Star, force=force)
    _chunk_delete_all(repo, AccessToken, force=force)
    _chunk_delete_all(repo, RepositoryNotification, force=force)
    _chunk_delete_all(repo, BlobUpload, force=force)
    _chunk_delete_all(repo, RepoMirrorConfig, force=force)
    _chunk_delete_all(repo, RepositoryAuthorizedEmail, force=force)

    # Delete any marker rows for the repository.
    DeletedRepository.delete().where(
        DeletedRepository.repository == repo).execute()

    # Delete the rest of the repository metadata.
    try:
        # Make sure the repository still exists.
        fetched = Repository.get(id=repo.id)
    except Repository.DoesNotExist:
        return False

    fetched.delete_instance(recursive=True, delete_nullable=False, force=force)
    return True
Esempio n. 11
0
File: tag.py Progetto: zhill/quay
def lookup_unrecoverable_tags(repo):
    """ Returns the tags  in a repository that are expired and past their time machine recovery
      period. """
    expired_clause = get_epoch_timestamp() - Namespace.removed_tag_expiration_s
    return (RepositoryTag.select().join(Repository).join(
        Namespace, on=(Repository.namespace_user == Namespace.id)).where(
            RepositoryTag.repository == repo).where(
                ~(RepositoryTag.lifetime_end_ts >> None),
                RepositoryTag.lifetime_end_ts <= expired_clause,
            ))
Esempio n. 12
0
def test_get_matching_tag_ids_for_all_images(max_subqueries, max_image_lookup_count, initialized_db):
  with patch('data.model.tag._MAX_SUB_QUERIES', max_subqueries):
    with patch('data.model.tag._MAX_IMAGE_LOOKUP_COUNT', max_image_lookup_count):
      pairs = []
      for image in Image.select(Image, ImageStorage).join(ImageStorage):
        pairs.append((image.docker_image_id, image.storage.uuid))

      expected_tags_ids = set([tag.id for tag in _tag_alive(RepositoryTag.select())])
      matching_tags_ids = set([tag.id for tag in get_matching_tags_for_images(pairs)])

      # Ensure every alive tag was found.
      assert matching_tags_ids == expected_tags_ids
Esempio n. 13
0
def upgrade_progress():
  total_tags = RepositoryTag.select().where(RepositoryTag.hidden == False).count()
  if total_tags == 0:
    return jsonify({
      'progress': 1.0,
      'tags_remaining': 0,
      'total_tags': 0,
    })

  upgraded_tags = TagToRepositoryTag.select().count()
  return jsonify({
    'progress': float(upgraded_tags) / total_tags,
    'tags_remaining': total_tags - upgraded_tags,
    'total_tags': total_tags,
  })
Esempio n. 14
0
File: tag.py Progetto: zhill/quay
def delete_tag(namespace_name, repository_name, tag_name, now_ms=None):
    now_ms = now_ms or get_epoch_timestamp_ms()
    now_ts = int(now_ms / 1000)

    with db_transaction():
        try:
            query = _tag_alive(
                RepositoryTag.select(
                    RepositoryTag, Repository).join(Repository).join(
                        Namespace,
                        on=(Repository.namespace_user == Namespace.id)).where(
                            Repository.name == repository_name,
                            Namespace.username == namespace_name,
                            RepositoryTag.name == tag_name,
                        ),
                now_ts,
            )
            found = db_for_update(query).get()
        except RepositoryTag.DoesNotExist:
            msg = "Invalid repository tag '%s' on repository '%s/%s'" % (
                tag_name,
                namespace_name,
                repository_name,
            )
            raise DataModelException(msg)

        found.lifetime_end_ts = now_ts
        found.save()

        try:
            oci_tag_query = TagToRepositoryTag.select().where(
                TagToRepositoryTag.repository_tag == found)
            oci_tag = db_for_update(oci_tag_query).get().tag
            oci_tag.lifetime_end_ms = now_ms
            oci_tag.save()
        except TagToRepositoryTag.DoesNotExist:
            pass

        return found
Esempio n. 15
0
File: tag.py Progetto: zhill/quay
def list_repository_tags(namespace_name,
                         repository_name,
                         include_hidden=False,
                         include_storage=False):
    to_select = (RepositoryTag, Image)
    if include_storage:
        to_select = (RepositoryTag, Image, ImageStorage)

    query = _tag_alive(
        RepositoryTag.select(*to_select).join(Repository).join(
            Namespace, on=(Repository.namespace_user == Namespace.id
                           )).switch(RepositoryTag).join(Image).where(
                               Repository.name == repository_name,
                               Namespace.username == namespace_name))

    if not include_hidden:
        query = query.where(RepositoryTag.hidden == False)

    if include_storage:
        query = query.switch(Image).join(ImageStorage)

    return query
Esempio n. 16
0
File: tag.py Progetto: zhill/quay
def get_max_id_for_sec_scan():
    """ Gets the maximum id for security scanning """
    return RepositoryTag.select(fn.Max(RepositoryTag.id)).scalar()