mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 05:23:35 +00:00
export: Add option to upload exports to S3.
This should make it more convenient to operationalize providing exports from Zulip Cloud. Fixes #11178.
This commit is contained in:
@@ -2,15 +2,18 @@
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from argparse import ArgumentParser, RawTextHelpFormatter
|
||||
from typing import Any
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import CommandError
|
||||
|
||||
from zerver.lib.export import do_export_realm, \
|
||||
do_write_stats_file_for_realm_export
|
||||
from zerver.lib.management import ZulipBaseCommand
|
||||
from zerver.lib.utils import generate_random_token
|
||||
|
||||
class Command(ZulipBaseCommand):
|
||||
help = """Exports all data from a Zulip realm
|
||||
@@ -97,6 +100,9 @@ class Command(ZulipBaseCommand):
|
||||
action="store",
|
||||
default=6,
|
||||
help='Threads to use in exporting UserMessage objects in parallel')
|
||||
parser.add_argument('--upload-to-s3',
|
||||
action="store_true",
|
||||
help="Whether to upload resulting tarball to s3")
|
||||
self.add_realm_args(parser, True)
|
||||
|
||||
def handle(self, *args: Any, **options: Any) -> None:
|
||||
@@ -125,3 +131,29 @@ class Command(ZulipBaseCommand):
|
||||
os.chdir(os.path.dirname(output_dir))
|
||||
subprocess.check_call(["tar", "-czf", tarball_path, os.path.basename(output_dir)])
|
||||
print("Tarball written to %s" % (tarball_path,))
|
||||
|
||||
if not options["upload_to_s3"]:
|
||||
return
|
||||
|
||||
def percent_callback(complete: Any, total: Any) -> None:
|
||||
sys.stdout.write('.')
|
||||
sys.stdout.flush()
|
||||
|
||||
if settings.LOCAL_UPLOADS_DIR is not None:
|
||||
raise CommandError("S3 backend must be configured to upload to S3")
|
||||
|
||||
print("Uploading export tarball to S3")
|
||||
|
||||
from zerver.lib.upload import S3Connection, get_bucket, Key
|
||||
conn = S3Connection(settings.S3_KEY, settings.S3_SECRET_KEY)
|
||||
# We use the avatar bucket, because it's world-readable.
|
||||
bucket = get_bucket(conn, settings.S3_AVATAR_BUCKET)
|
||||
key = Key(bucket)
|
||||
key.key = os.path.join("exports", generate_random_token(32), os.path.basename(tarball_path))
|
||||
key.set_contents_from_filename(tarball_path, cb=percent_callback, num_cb=40)
|
||||
|
||||
public_url = 'https://{bucket}.{host}/{key}'.format(
|
||||
host=conn.server_name(),
|
||||
bucket=bucket.name,
|
||||
key=key.key)
|
||||
print("Uploaded to %s" % (public_url,))
|
||||
|
||||
Reference in New Issue
Block a user