87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
import json
|
|
import os
|
|
import pwd
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
def cli():
|
|
"""
|
|
Performs a backup of a MySQL database.
|
|
|
|
Parameters:
|
|
database: str — the name of the database to back up.
|
|
|
|
user: optional str — the name of the Linux user to use to connect to MySQL.
|
|
Sudo or SSH will be used to make this happen, if it's specified,
|
|
unless it's a local user that is already the current user.
|
|
|
|
host: optional str — if specified, the backup will be made using SSH
|
|
(unless this host is the same as the one named)
|
|
"""
|
|
request_info = json.load(sys.stdin)
|
|
assert isinstance(request_info, dict)
|
|
|
|
database_to_use = request_info["database"]
|
|
user_to_use = request_info.get("user")
|
|
host_to_use = request_info.get("host")
|
|
use_lz4 = request_info.get("use_lz4_for_ssh", True)
|
|
|
|
if host_to_use is not None:
|
|
hostname = subprocess.check_output("hostname").decode().strip()
|
|
if hostname == host_to_use:
|
|
host_to_use = None
|
|
|
|
command = []
|
|
|
|
if host_to_use is not None:
|
|
command.append("ssh")
|
|
if user_to_use is not None:
|
|
command.append(f"{user_to_use}@{host_to_use}")
|
|
else:
|
|
command.append(f"{host_to_use}")
|
|
elif user_to_use is not None:
|
|
current_username = pwd.getpwuid(os.getuid()).pw_name
|
|
if current_username != user_to_use:
|
|
command.append("sudo")
|
|
command.append("-u")
|
|
command.append(user_to_use)
|
|
|
|
command.append("mysqldump")
|
|
command.append(database_to_use)
|
|
|
|
# Where the output of the dump command should go.
|
|
output_of_dump = sys.stdout
|
|
# The process (if any) that is our LZ4 decompressor.
|
|
lz4_process = None
|
|
|
|
if use_lz4 and host_to_use is not None:
|
|
# Add an LZ4 compressor on the remote side.
|
|
command += ["|", "lz4", "--compress", "--stdout"]
|
|
|
|
# Then open an LZ4 decompressor on our side.
|
|
lz4_process = subprocess.Popen(
|
|
["lz4", "--decompress", "--stdout"],
|
|
stdin=subprocess.PIPE,
|
|
stdout=sys.stdout,
|
|
stderr=sys.stderr,
|
|
)
|
|
output_of_dump = lz4_process.stdin
|
|
|
|
# we MUST disable shell here otherwise the local side will do both
|
|
# the compression and decompression which would be silly!
|
|
subprocess.check_call(
|
|
command,
|
|
stdin=subprocess.DEVNULL,
|
|
stdout=output_of_dump,
|
|
stderr=sys.stderr,
|
|
shell=False,
|
|
)
|
|
|
|
if lz4_process is not None:
|
|
# must close here, otherwise the decompressor never ends
|
|
lz4_process.stdin.close()
|
|
exit_code = lz4_process.wait()
|
|
if exit_code != 0:
|
|
raise ChildProcessError(f"lz4 not happy: {exit_code}")
|