Ctrl K
ComunidadGuías…

scripts/migrate_s3_objects.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env python3
"""Copy the stored objects (files, refused emails) to the new S3 bucket.

The app must already be configured for the new storage (config.BUCKET,
AWS_ENDPOINT_URL) before running this: the script reads the keys from the DB
and writes them to whatever bucket the config points at. The old storage is
the publicly readable one, given as --old-root. Keys are kept identical, so
no DB row is touched, and old objects are never deleted.

    # 1. switch the config to the new bucket and deploy
    # 2. dry run to see what would be copied
    python scripts/migrate_s3_objects.py --old-root https://old-static.example.com
    # 3. do it
    python scripts/migrate_s3_objects.py --old-root https://old-static.example.com --apply
    # 4. rerun the --apply pass later to pick up the rows created in between

To resume an interrupted run, pass the highest --start-id the log reached.
Use --only to handle one model at a time.
"""

import argparse
import sys
from collections import Counter

from app import config
from app.log import LOG
from app.s3_migration import iter_keys, migrate_key


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "--old-root",
        required=True,
        help="root URL of the old storage, must start with https://",
    )
    parser.add_argument(
        "--apply",
        action="store_true",
        help="upload the missing objects. Without it nothing is uploaded",
    )
    parser.add_argument(
        "--batch-size",
        type=int,
        default=1000,
        help="how many ids to look at per query",
    )
    parser.add_argument(
        "--start-id",
        type=int,
        default=0,
        help="skip the rows with an id <= this, to resume an interrupted run",
    )
    parser.add_argument(
        "--only",
        choices=["file", "refused_email"],
        help="handle only this model",
    )
    parser.add_argument(
        "--timeout",
        type=float,
        default=30.0,
        help="seconds to wait for the old storage per request",
    )
    args = parser.parse_args()

    if not args.old_root.startswith("https://"):
        LOG.e("--old-root must start with https://")
        return 1

    if config.LOCAL_FILE_UPLOAD:
        LOG.e(
            "LOCAL_FILE_UPLOAD is set: the config still points at the local "
            "disk. Configure the new S3 storage first"
        )
        return 1

    counts: Counter = Counter()
    for model_name, row_id, key in iter_keys(
        args.batch_size, only=args.only, start_id=args.start_id
    ):
        outcome = migrate_key(key, args.old_root, args.apply, args.timeout)
        counts[outcome] += 1
        LOG.i(f"{outcome.value}: {model_name} {row_id} {key}")

    mode = "applied" if args.apply else "dry run"
    LOG.i(f"Done ({mode}): " + ", ".join(f"{o.value}={c}" for o, c in counts.items()))
    return 0


if __name__ == "__main__":
    sys.exit(main())