backup: Use tar --transform to arrange the tarball instead of symlinks.

This allows tar to print the real paths in error messages if something
goes wrong.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
This commit is contained in:
Anders Kaseorg
2019-04-12 16:48:34 -07:00
committed by Tim Abbott
parent abe645f1d3
commit e074165c1b
2 changed files with 41 additions and 17 deletions

View File

@@ -2,6 +2,7 @@
import argparse
import os
import re
import subprocess
import sys
import tempfile
@@ -56,13 +57,16 @@ if __name__ == "__main__":
os.chown(path, uid, gid)
os.setresuid(uid, uid, 0)
# We create symlinks so that we can do a single `tar -x`
# command to unpack the uploads, settings, etc. to their
# appropriate places.
assert not any("|" in name or "|" in path for name, path in paths)
transform_args = [
r"--transform=s|^zulip-backup/{}(/.*)?$|{}\1|x".format(
re.escape(name), path.replace("\\", r"\\")
)
for name, path in paths
]
os.mkdir(os.path.join(tmp, "zulip-backup"))
for name, path in paths:
os.symlink(path, os.path.join(tmp, "zulip-backup", name))
run(["tar", "-C", tmp, "--keep-directory-symlink", "-xzf", args.tarball])
run(["tar", "-C", tmp] + transform_args + ["-xPzf", args.tarball])
# Now, restore the the database backup using pg_restore.
db_name = settings.DATABASES["default"]["NAME"]

View File

@@ -1,4 +1,5 @@
import os
import re
import tempfile
from argparse import ArgumentParser, RawTextHelpFormatter
from typing import Any
@@ -33,6 +34,7 @@ class Command(ZulipBaseCommand):
) as tmp:
os.mkdir(os.path.join(tmp, "zulip-backup"))
members = []
paths = []
with open(os.path.join(tmp, "zulip-backup", "zulip-version"), "w") as f:
print(ZULIP_VERSION, file=f)
@@ -53,14 +55,15 @@ class Command(ZulipBaseCommand):
members.append("zulip-backup/postgres-version")
if settings.DEVELOPMENT:
os.symlink(
os.path.join(settings.DEPLOY_ROOT, "zproject"),
os.path.join(tmp, "zulip-backup", "zproject"),
members.append(
os.path.join(settings.DEPLOY_ROOT, "zproject", "dev-secrets.conf")
)
paths.append(
("zproject", os.path.join(settings.DEPLOY_ROOT, "zproject"))
)
members.append("zulip-backup/zproject/dev-secrets.conf")
else:
os.symlink("/etc/zulip", os.path.join(tmp, "zulip-backup", "settings"))
members.append("zulip-backup/settings")
members.append("/etc/zulip")
paths.append(("settings", "/etc/zulip"))
db_name = settings.DATABASES["default"]["NAME"]
db_dir = os.path.join(tmp, "zulip-backup", "database")
@@ -73,11 +76,23 @@ class Command(ZulipBaseCommand):
if settings.LOCAL_UPLOADS_DIR is not None and os.path.exists(
os.path.join(settings.DEPLOY_ROOT, settings.LOCAL_UPLOADS_DIR)
):
os.symlink(
os.path.join(settings.DEPLOY_ROOT, settings.LOCAL_UPLOADS_DIR),
os.path.join(tmp, "zulip-backup", "uploads"),
members.append(
os.path.join(settings.DEPLOY_ROOT, settings.LOCAL_UPLOADS_DIR)
)
members.append("zulip-backup/uploads")
paths.append(
(
"uploads",
os.path.join(settings.DEPLOY_ROOT, settings.LOCAL_UPLOADS_DIR),
)
)
assert not any("|" in name or "|" in path for name, path in paths)
transform_args = [
r"--transform=s|^{}(/.*)?$|zulip-backup/{}\1|x".format(
re.escape(path), name.replace("\\", r"\\")
)
for name, path in paths
]
try:
if options["output"] is None:
@@ -89,7 +104,12 @@ class Command(ZulipBaseCommand):
else:
tarball_path = options["output"]
run(["tar", "-C", tmp, "-chzf", tarball_path, "--"] + members)
run(
["tar", "-C", tmp, "-cPzf", tarball_path]
+ transform_args
+ ["--"]
+ members
)
print("Backup tarball written to %s" % (tarball_path,))
except BaseException:
if options["output"] is None: