Implement recover command

This commit is contained in:
deajan 2024-09-05 20:12:18 +02:00
parent 0fdda44197
commit 3686dfa75e
6 changed files with 55 additions and 3 deletions

View file

@ -165,6 +165,9 @@ This is free software, and you are welcome to redistribute it under certain cond
parser.add_argument(
"--repair-snapshots", action="store_true", help="Repair repo snapshots"
)
parser.add_argument(
"--recover", action="store_true", help="Recover lost repo snapshots"
)
parser.add_argument(
"--list",
type=str,
@ -276,7 +279,7 @@ This is free software, and you are welcome to redistribute it under certain cond
type=str,
default=None,
required=False,
help="Launch an operation on a group of repositories given by --repo-group or --repo-name. Valid group operations are [backup|restore|snapshots|list|ls|find|policy|quick_check|full_check|prune|prune_max|unlock|repair_index|repair_packs|repair_snapshots|dump|stats|raw|has_recent_snapshot]",
help="Launch an operation on a group of repositories given by --repo-group or --repo-name. Valid group operations are [backup|restore|snapshots|list|ls|find|policy|quick_check|full_check|prune|prune_max|unlock|repair_index|repair_packs|repair_snapshots|recover|dump|stats|raw|has_recent_snapshot]",
)
parser.add_argument(
"--create-key",
@ -554,6 +557,8 @@ This is free software, and you are welcome to redistribute it under certain cond
elif args.repair_snapshots or args.group_operation == "repair_snapshots":
cli_args["operation"] = "repair"
cli_args["op_args"] = {"subject": "snapshots"}
elif args.recover or args.group_operation == "recover":
cli_args["operation"] = "recover"
elif args.dump or args.group_operation == "dump":
cli_args["operation"] = "dump"
cli_args["op_args"] = {"path": args.dump}
@ -586,13 +591,14 @@ This is free software, and you are welcome to redistribute it under certain cond
"repair_index",
"repair_packs",
"repair_snapshots",
"recover",
"dump",
"stats",
"raw",
"has_recent_snapshot",
):
logger.critical(
f"Invalid group operation {args.group_operation}. Valid operations are [backup|restore|snapshots|list|ls|find|policy|housekeeping|quick_check|full_check|prune|prune_max|unlock|repair_index|repair_packs|repair_snapshots|dump|stats|raw|has_recent_snapshot]"
f"Invalid group operation {args.group_operation}. Valid operations are [backup|restore|snapshots|list|ls|find|policy|housekeeping|quick_check|full_check|prune|prune_max|unlock|repair_index|repair_packs|repair_snapshots|recover|dump|stats|raw|has_recent_snapshot]"
)
sys.exit(74)
repo_config_list = []

View file

@ -472,6 +472,7 @@ class NPBackupRunner:
"restore": ["restore", "full"],
"dump": ["restore", "full"],
"check": ["restore", "full"],
"recover": ["restore", "full"],
"init": ["full"],
"list": ["full"],
"unlock": ["full"],
@ -1437,6 +1438,21 @@ class NPBackupRunner:
)
return self.restic_runner.repair(subject, pack_ids)
@threaded
@catch_exceptions
@metrics
@close_queues
@exec_timer
@check_concurrency
@has_permission
@is_ready
@apply_config_to_restic_runner
def recover(self) -> bool:
self.write_logs(
f"Recovering snapshots in repo {self.repo_config.g('name')}", level="info"
)
return self.restic_runner.recover()
@threaded
@catch_exceptions
@metrics

View file

@ -195,6 +195,13 @@ def operations_gui(full_config: dict) -> dict:
sg.Button(
_t("operations_gui.unlock"), key="--UNLOCK--", size=(45, 1)
),
sg.Button(
_t("operations_gui.recover"),
key="--RECOVER--",
size=(45, 1),
),
],
[
sg.Button(
_t("operations_gui.stats"),
key="--STATS--",
@ -266,6 +273,7 @@ def operations_gui(full_config: dict) -> dict:
"--REPAIR-INDEX--",
"--REPAIR-PACKS--",
"--REPAIR-SNAPSHOTS--",
"--RECOVER--",
"--UNLOCK--",
"--FORGET--",
"--STANDARD-PRUNE--",
@ -317,11 +325,15 @@ def operations_gui(full_config: dict) -> dict:
"subject": "packs",
"pack_ids": pack_ids,
}
gui_msg = _t("operations_gui.repair_pack")
gui_msg = _t("operations_gui.repair_packs")
if event == "--REPAIR-SNAPSHOTS--":
operation = "repair"
op_args = {"subject": "snapshots"}
gui_msg = _t("operations_gui.repair_snapshots")
if event == "--RECOVER--":
operation = "recover"
op_args = {}
gui_msg = _t("operations_gui.recover")
if event == "--STANDARD-PRUNE--":
operation = "prune"
op_args = {}

View file

@ -1095,6 +1095,22 @@ class ResticRunner:
msg = f"Repo repair failed:\n{output}"
return self.convert_to_json_output(result, output, msg=msg, **kwargs)
@check_if_init
def recover(self) -> Union[bool, str, dict]:
"""
Try to recover lost snapshots
"""
kwargs = locals()
kwargs.pop("self")
cmd = f"recover"
result, output = self.executor(cmd)
if result:
msg = f"Recovery succees"
else:
msg = f"Recovery failed:\n{output}"
return self.convert_to_json_output(result, output, msg=msg, **kwargs)
@check_if_init
def unlock(self) -> Union[bool, str, dict]:
"""

View file

@ -6,6 +6,7 @@ en:
repair_packs: Repair repo packs
pack_ids: Pack IDs
repair_snapshots: Repair repo snapshots
recover: Recover deleted snapshots
unlock: Unlock repo
forget_using_retention_policy: Forget using retention polic
standard_prune: Normal prune data

View file

@ -6,6 +6,7 @@ fr:
repair_packs: Réparer les blocs du dépot
pack_ids: Identifiants de blocs
repair_snapshots: Réparer les instantanés du dépot
recover: Récupérer des instantanés supprimés
unlock: Déblocage de dépot
forget_using_retention_policy: Oublier les instantanés en utilisant la stratégie de rétention
standard_prune: Opération de purge normale