Skip to content

Commit

Permalink
plug-in func to backup_auto_folders (for aiida-core)
Browse files Browse the repository at this point in the history
  • Loading branch information
eimrek committed Nov 2, 2023
1 parent b5a30f2 commit 15bdb18
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 26 deletions.
63 changes: 38 additions & 25 deletions disk_objectstore/backup_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import subprocess
import tempfile
from pathlib import Path
from typing import Optional
from typing import Callable, Optional

from disk_objectstore.container import Container

Expand All @@ -35,7 +35,9 @@ def is_exe_found(exe: str) -> bool:


class BackupUtilities:
"""Utilities to make a backup of the disk-objectstore container"""
"""Utilities to make a backup of the disk-objectstore container
and to manage backups in general (designed to also be used by aiida-core)
"""

def __init__(
self, dest: str, keep: int, rsync_exe: str, logger_: logging.Logger
Expand All @@ -46,6 +48,9 @@ def __init__(
self.logger = logger_
self.remote, self.path = split_remote_and_path(dest)

Check warning on line 49 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L45-L49

Added lines #L45 - L49 were not covered by tests

# subprocess arguments shared by all rsync calls:
self.rsync_args = [self.rsync_exe, "-azh", "-vv", "--no-whole-file"]

Check warning on line 52 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L52

Added line #L52 was not covered by tests

def run_cmd(self, args: list):
"""
Run a command locally or remotely.
Expand Down Expand Up @@ -81,7 +86,7 @@ def check_path_exists(self, path: Path) -> bool:
cmd = ["[", "-e", str(path), "]"]
return self.run_cmd(cmd)[0]

Check warning on line 87 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L86-L87

Added lines #L86 - L87 were not covered by tests

def validate_inputs(self) -> bool:
def validate_inputs(self, additional_exes: Optional[list] = None) -> bool:
"""Validate inputs to the backup cli command
:return:
Expand All @@ -99,6 +104,12 @@ def validate_inputs(self) -> bool:
self.logger.error(f"{self.rsync_exe} not accessible.")
return False

Check warning on line 105 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L103-L105

Added lines #L103 - L105 were not covered by tests

if additional_exes:
for add_exe in additional_exes:
if not is_exe_found(add_exe):
self.logger.error(f"{add_exe} not accessible.")
return False

Check warning on line 111 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L107-L111

Added lines #L107 - L111 were not covered by tests

path_exists = self.check_path_exists(self.path)

Check warning on line 113 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L113

Added line #L113 was not covered by tests

if not path_exists:
Expand All @@ -111,12 +122,12 @@ def validate_inputs(self) -> bool:

def call_rsync( # pylint: disable=too-many-arguments
self,
args: list,
src: Path,
dest: Path,
link_dest: Optional[Path] = None,
src_trailing_slash: bool = False,
dest_trailing_slash: bool = False,
extra_args: Optional[list] = None,
) -> bool:
"""Call rsync with specified arguments and handle possible errors & stdout/stderr
Expand All @@ -135,7 +146,9 @@ def call_rsync( # pylint: disable=too-many-arguments
True if successful and False if unsuccessful.
"""

all_args = args[:]
all_args = self.rsync_args[:]
if extra_args:
all_args += extra_args
if link_dest:
if not self.remote:

Check warning on line 153 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L149-L153

Added lines #L149 - L153 were not covered by tests
# for local paths, use resolve() to get absolute path
Expand Down Expand Up @@ -197,9 +210,6 @@ def backup_container( # pylint: disable=too-many-return-statements, too-many-br
True if successful and False if unsuccessful.
"""

# subprocess arguments shared by all rsync calls:
rsync_args = [self.rsync_exe, "-azh", "-vv", "--no-whole-file"]

container_root_path = container.get_folder()
loose_path = container._get_loose_folder() # pylint: disable=protected-access
packs_path = container._get_pack_folder() # pylint: disable=protected-access
Expand All @@ -210,9 +220,7 @@ def backup_container( # pylint: disable=too-many-return-statements, too-many-br
# step 1: back up loose files
loose_path_rel = loose_path.relative_to(container_root_path)
prev_backup_loose = prev_backup / loose_path_rel if prev_backup else None
success = self.call_rsync(
rsync_args, loose_path, path, link_dest=prev_backup_loose
)
success = self.call_rsync(loose_path, path, link_dest=prev_backup_loose)
if not success:
return False
self.logger.info(f"Transferred {str(loose_path)} to {str(path)}")

Check warning on line 226 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L221-L226

Added lines #L221 - L226 were not covered by tests
Expand Down Expand Up @@ -241,35 +249,32 @@ def backup_container( # pylint: disable=too-many-return-statements, too-many-br
return False

Check warning on line 249 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L248-L249

Added lines #L248 - L249 were not covered by tests

# step 3: transfer the SQLITE database file
success = self.call_rsync(
rsync_args, sqlite_temp_loc, path, link_dest=prev_backup
)
success = self.call_rsync(sqlite_temp_loc, path, link_dest=prev_backup)
if not success:
return False
self.logger.info(f"Transferred SQLite database to {str(path)}")

Check warning on line 255 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L252-L255

Added lines #L252 - L255 were not covered by tests

# step 4: transfer the packed files
packs_path_rel = packs_path.relative_to(container_root_path)
success = self.call_rsync(rsync_args, packs_path, path, link_dest=prev_backup)
success = self.call_rsync(packs_path, path, link_dest=prev_backup)
if not success:
return False
self.logger.info(f"Transferred {str(packs_path)} to {str(path)}")

Check warning on line 262 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L258-L262

Added lines #L258 - L262 were not covered by tests

# step 5: transfer anything else in the container folder
success = self.call_rsync(

Check warning on line 265 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L265

Added line #L265 was not covered by tests
rsync_args
+ [
container_root_path,
path,
link_dest=prev_backup,
src_trailing_slash=True,
extra_args=[
"--exclude",
str(loose_path_rel),
"--exclude",
"packs.idx",
"--exclude",
str(packs_path_rel),
],
container_root_path,
path,
link_dest=prev_backup,
src_trailing_slash=True,
)
if not success:
return False

Check warning on line 280 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L279-L280

Added lines #L279 - L280 were not covered by tests
Expand Down Expand Up @@ -306,7 +311,7 @@ def delete_old_backups(self) -> bool:

def backup_auto_folders(
self,
container: Container,
backup_function: Callable,
):
"""Create a backup, managing live and previous backup folders automatically
Expand All @@ -315,6 +320,10 @@ def backup_auto_folders(
be set to point to it. Rsync `link-dest` is used between live-backup and last-backup
to keep the backups incremental and performant.
:param backup_function:
Function that is used to make a single backup. Needs to have two arguments: path and
previous_backup location (which can be None).
:param path:
Path to where the backup will be created. If 'remote' is specified, must be an absolute path,
otherwise can be relative.
Expand All @@ -336,10 +345,14 @@ def backup_auto_folders(
f"'{str(last_symlink)}' exists, using it for rsync --link-dest."
)

success = self.backup_container(
container,
# success = self.backup_container(
# container,
# live_folder,
# prev_backup=last_symlink if prev_exists else None,
# )
success = backup_function(

Check warning on line 353 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L353

Added line #L353 was not covered by tests
live_folder,
prev_backup=last_symlink if prev_exists else None,
last_symlink if prev_exists else None,
)
if not success:
return False

Check warning on line 358 in disk_objectstore/backup_utils.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/backup_utils.py#L357-L358

Added lines #L357 - L358 were not covered by tests
Expand Down
6 changes: 5 additions & 1 deletion disk_objectstore/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,11 @@ def backup(
return

Check warning on line 248 in disk_objectstore/cli.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/cli.py#L245-L248

Added lines #L245 - L248 were not covered by tests

with dostore.container as container:
success = backup_utils_instance.backup_auto_folders(container)
success = backup_utils_instance.backup_auto_folders(

Check warning on line 251 in disk_objectstore/cli.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/cli.py#L250-L251

Added lines #L250 - L251 were not covered by tests
lambda path, prev: backup_utils_instance.backup_container(
container, path, prev_backup=prev
)
)
if not success:
click.echo("Error: backup failed.")
return

Check warning on line 258 in disk_objectstore/cli.py

View check run for this annotation

Codecov / codecov/patch

disk_objectstore/cli.py#L256-L258

Added lines #L256 - L258 were not covered by tests

0 comments on commit 15bdb18

Please sign in to comment.