Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy and paste the old commands #292

Open
wants to merge 29 commits into
base: gabor/implement-cli
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7a17bc6
:construction: WIP Start porting dump command
Jul 1, 2022
5fd2acb
:construction: Copying the cli export from the old driver
Jul 13, 2022
c3367da
:construction: Fix some import errors
Jul 14, 2022
6aea50b
:construction: Copy import and fix f-strings
Jul 14, 2022
e625464
:bug: Fix Syntax errors in cli's import
Jul 16, 2022
44fa648
:construction: Copy and add f-strings to index_rebuild
Jul 16, 2022
3b479a3
:bug: Fix indentation
Jul 16, 2022
ffc66eb
:bug: Fix syntax errors
Jul 16, 2022
ad82769
:bug: Fix syntax errors
Jul 16, 2022
54d00eb
:bug: Fix bytes_processed exception when reading file with small buff…
Aug 9, 2022
523c8b1
:sparkles: Ported the restore module
Oct 1, 2022
b7ae9d0
:construction: Add click options to dump
Nov 27, 2022
753bb1f
:construction: Remove the click library reference
lsabi Sep 17, 2023
a50f822
:construction: Remove the click command library references
lsabi Sep 17, 2023
96ccdd4
:construction: Remove the click library
lsabi Sep 17, 2023
babc139
:construction: Remove click library
lsabi Sep 17, 2023
0ae82d1
:construction: Remove click command
lsabi Sep 17, 2023
b29254b
:bug: Fix tabs to spaces
lsabi Sep 17, 2023
5e9b422
:bug: Change tabs into spaces
lsabi Sep 17, 2023
cab859e
:bug: Fix indentation
lsabi Sep 17, 2023
b37603b
:bug: Remove click library
lsabi Sep 17, 2023
2a3f9c2
:bug: Remove click library
lsabi Sep 17, 2023
a5e7ef9
:bug: Remove click library
lsabi Sep 17, 2023
9705f56
:bug: Update old references to _export.py that caused crash
lsabi Sep 17, 2023
cc3b654
:bug: Remove click library
lsabi Sep 17, 2023
aff0afa
:bug: Remove click library
lsabi Sep 17, 2023
2fba967
:bug: Fix indentation
lsabi Sep 17, 2023
847ebde
Port utils_common.py from old driver version
Sep 17, 2023
6b23a75
Fix missing references and packages from porting the old driver
Sep 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion rethinkdb/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
Although these commands can be used to prepare data for backup, depending on
your needs, you may want to evaluate more mature backup backup solutions.
"""

"""
from rethinkdb.cli._dump import cmd_dump
from rethinkdb.cli._export import cmd_export
from rethinkdb.cli._import import cmd_import
from rethinkdb.cli._index_rebuild import cmd_index_rebuild
from rethinkdb.cli._repl import cmd_repl
from rethinkdb.cli._restore import cmd_restore
"""
238 changes: 231 additions & 7 deletions rethinkdb/cli/_dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,236 @@
"""
Dump creates an archive of data from a RethinkDB cluster.
"""
import click
import datetime
import os
import platform
import shutil
import sys
import tarfile
import tempfile
import time
import traceback

from rethinkdb.cli import utils_common, _export
# from rethinkdb.logger import default_logger

@click.command
def cmd_dump():
"""
Dump creates an archive of data from a RethinkDB cluster.
"""
click.echo("dump command")

usage = (
"rethinkdb dump [-c HOST:PORT] [-p] [--password-file FILENAME] [--tls-cert FILENAME] [-f FILE] "
"[--clients NUM] [-e (DB | DB.TABLE)]..."
)
help_epilog = """
EXAMPLES:
rethinkdb dump -c mnemosyne:39500
Archive all data from a cluster running on host 'mnemosyne' with a client port at 39500.

rethinkdb dump -e test -f rdb_dump.tar.gz
Archive only the 'test' database from a local cluster into a named file.

rethinkdb dump -c hades -e test.subscribers -p
Archive a specific table from a cluster running on host 'hades' which requires a password."""


def parse_options(argv, prog=None):
parser = utils_common.CommonOptionsParser(
usage=usage, epilog=help_epilog, prog=prog
)

parser.add_option(
"-f",
"--file",
dest="out_file",
metavar="FILE",
default=None,
help="file to write archive to (defaults to rethinkdb_dump_DATE_TIME.tar.gz);\nif FILE is -, use standard "
"output (note that intermediate files will still be written to the --temp-dir directory)",
)
parser.add_option(
"-e",
"--export",
dest="db_tables",
metavar="DB|DB.TABLE",
default=[],
type="db_table",
help="limit dump to the given database or table (may be specified multiple times)",
action="append",
)

parser.add_option(
"--temp-dir",
dest="temp_dir",
metavar="directory",
default=None,
help="the directory to use for intermediary results",
)
parser.add_option(
"--overwrite-file",
dest="overwrite",
default=False,
help="overwrite -f/--file if it exists",
action="store_true",
)
parser.add_option(
"--clients",
dest="clients",
metavar="NUM",
default=3,
help="number of tables to export simultaneously (default: 3)",
type="pos_int",
)
parser.add_option(
"--read-outdated",
dest="outdated",
default=False,
help="use outdated read mode",
action="store_true",
)

options, args = parser.parse_args(argv)

# Check validity of arguments
if len(args) != 0:
raise parser.error(
f"No positional arguments supported. Unrecognized option(s): {args}"
)

# Add dump name
if platform.system() == "Windows" or platform.system().lower().startswith("cygwin"):
options.dump_name = "rethinkdb_dump_%s" % datetime.datetime.today().strftime(
"%Y-%m-%dT%H-%M-%S"
) # no colons in name
else:
options.dump_name = f'rethinkdb_dump_{datetime.datetime.today().strftime("%Y-%m-%dT%H:%M:%S")}'

# Verify valid output file
if options.out_file == "-":
options.out_file = sys.stdout
options.quiet = True
elif options.out_file is None:
options.out_file = os.path.realpath(f"{options.dump_name}.tar.gz")
else:
options.out_file = os.path.realpath(options.out_file)

if options.out_file is not sys.stdout:
if os.path.exists(options.out_file) and not options.overwrite:
parser.error(f"Output file already exists: {options.out_file}")
if os.path.exists(options.out_file) and not os.path.isfile(options.out_file):
parser.error(
f"There is a non-file at the -f/--file location: {options.out_file}"
)

# Verify valid client count
if options.clients < 1:
raise RuntimeError(
f"Error: invalid number of clients ({options.clients}), must be greater than zero"
)

# Make sure the temporary directory exists and is accessible
if options.temp_dir is not None:
if not os.path.exists(options.temp_dir):
try:
os.makedirs(options.temp_dir)
except OSError:
parser.error(
"Could not create temporary directory: %s" % options.temp_dir
)
if not os.path.isdir(options.temp_dir):
parser.error(
f"Temporary directory doesn't exist or is not a directory: {options.temp_dir}"
)
if not os.access(options.temp_dir, os.W_OK):
parser.error(f"Temporary directory inaccessible: {options.temp_dir}")

return options


def main(argv=None, prog=None):
options = parse_options(argv or sys.argv[1:], prog=prog)
try:
if not options.quiet:
# Print a warning about the capabilities of dump, so no one is confused (hopefully)
print(
"""\
NOTE: 'rethinkdb-dump' saves data, secondary indexes, and write hooks, but does *not* save
cluster metadata. You will need to recreate your cluster setup yourself after
you run 'rethinkdb-restore'."""
)

try:
start_time = time.time()
archive = None

# -- _export options - need to be kep in-sync with _export

options.directory = os.path.realpath(tempfile.mkdtemp(dir=options.temp_dir))
options.fields = None
options.delimiter = None
options.format = "json"

# -- export to a directory

if not options.quiet:
print(" Exporting to temporary directory...")

try:
_export.run(options)
except Exception as exc:
default_logger.exception(exc)

if options.debug:
sys.stderr.write("\n%s\n" % traceback.format_exc())

raise Exception("Error: export failed, %s" % exc)

# -- zip directory

if not options.quiet:
print(" Zipping export directory...")

try:
if hasattr(options.out_file, "read"):
archive = tarfile.open(fileobj=options.out_file, mode="w:gz")
else:
archive = tarfile.open(name=options.out_file, mode="w:gz")
for curr, _, files in os.walk(os.path.realpath(options.directory)):
for data_file in files:
full_path = os.path.join(options.directory, curr, data_file)
archive_path = os.path.join(
options.dump_name,
os.path.relpath(full_path, options.directory),
)
archive.add(full_path, arcname=archive_path)
os.unlink(full_path)
finally:
if archive:
archive.close()

# --

if not options.quiet:
print(
"Done (%.2f seconds): %s"
% (
time.time() - start_time,
options.out_file.name
if hasattr(options.out_file, "name")
else options.out_file,
)
)
except KeyboardInterrupt:
time.sleep(0.2)
raise RuntimeError("Interrupted")
finally:
if os.path.exists(options.directory):
shutil.rmtree(options.directory)

except Exception as ex:
if options.debug:
traceback.print_exc()
print(ex, file=sys.stderr)
return 1
return 0


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