Beispiel #1
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
Beispiel #2
0
def mark_repository_for_deletion(namespace_name, repository_name, repository_gc_queue):
    """
    Marks a repository for future deletion in the background.

    The repository will be renamed and hidden, and then deleted later by a worker.
    """
    repo = get_repository(namespace_name, repository_name)
    if not repo:
        return None

    with db_transaction():
        # Delete any stars for the repository.
        Star.delete().where(Star.repository == repo).execute()

        # Change the name and state of the repository.
        repo.name = str(uuid.uuid4())
        repo.state = RepositoryState.MARKED_FOR_DELETION
        repo.save()

        # Create a tracking row and a queueitem to delete the repository.
        marker = DeletedRepository.create(repository=repo, original_name=repository_name)

        # Add a queueitem to delete the repository.
        marker.queue_id = repository_gc_queue.put(
            [namespace_name, str(repo.id)],
            json.dumps({"marker_id": marker.id, "original_name": repository_name,}),
        )
        marker.save()

    # Run callbacks for the deleted repo.
    for callback in config.repo_cleanup_callbacks:
        callback(namespace_name, repository_name)

    return marker.id