From 0fdda44197c2905fafe72691ec4b870694e48238 Mon Sep 17 00:00:00 2001 From: deajan Date: Thu, 5 Sep 2024 20:01:37 +0200 Subject: [PATCH] Implement repair pack command --- npbackup/__main__.py | 17 +++++++++++++++-- npbackup/core/runner.py | 4 ++-- npbackup/gui/operations.py | 21 +++++++++++++++++++-- npbackup/restic_wrapper/__init__.py | 6 ++++-- npbackup/translations/operations_gui.en.yml | 2 ++ npbackup/translations/operations_gui.fr.yml | 2 ++ 6 files changed, 44 insertions(+), 8 deletions(-) diff --git a/npbackup/__main__.py b/npbackup/__main__.py index 101786b..27b0dea 100644 --- a/npbackup/__main__.py +++ b/npbackup/__main__.py @@ -156,6 +156,12 @@ This is free software, and you are welcome to redistribute it under certain cond ) parser.add_argument("--unlock", action="store_true", help="Unlock repository") parser.add_argument("--repair-index", action="store_true", help="Repair repo index") + parser.add_argument( + "--repair-packs", + default=None, + required=False, + help="Repair repo packs ids given by --repair-packs", + ) parser.add_argument( "--repair-snapshots", action="store_true", help="Repair repo snapshots" ) @@ -270,7 +276,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_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|dump|stats|raw|has_recent_snapshot]", ) parser.add_argument( "--create-key", @@ -539,6 +545,12 @@ This is free software, and you are welcome to redistribute it under certain cond elif args.repair_index or args.group_operation == "repair_index": cli_args["operation"] = "repair" cli_args["op_args"] = {"subject": "index"} + elif args.repair_packs or args.group_operation == "repair_packs": + cli_args["operation"] = "repair" + cli_args["op_args"] = { + "subject": "packs", + "pack_ids": args.repair_packs, + } elif args.repair_snapshots or args.group_operation == "repair_snapshots": cli_args["operation"] = "repair" cli_args["op_args"] = {"subject": "snapshots"} @@ -572,6 +584,7 @@ This is free software, and you are welcome to redistribute it under certain cond "prune_max", "unlock", "repair_index", + "repair_packs", "repair_snapshots", "dump", "stats", @@ -579,7 +592,7 @@ This is free software, and you are welcome to redistribute it under certain cond "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_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|dump|stats|raw|has_recent_snapshot]" ) sys.exit(74) repo_config_list = [] diff --git a/npbackup/core/runner.py b/npbackup/core/runner.py index 9f82e7c..c29c1d4 100644 --- a/npbackup/core/runner.py +++ b/npbackup/core/runner.py @@ -1431,11 +1431,11 @@ class NPBackupRunner: @has_permission @is_ready @apply_config_to_restic_runner - def repair(self, subject: str) -> bool: + def repair(self, subject: str, pack_ids: str = None) -> bool: self.write_logs( f"Repairing {subject} in repo {self.repo_config.g('name')}", level="info" ) - return self.restic_runner.repair(subject) + return self.restic_runner.repair(subject, pack_ids) @threaded @catch_exceptions diff --git a/npbackup/gui/operations.py b/npbackup/gui/operations.py index 4c519d0..693bbcc 100644 --- a/npbackup/gui/operations.py +++ b/npbackup/gui/operations.py @@ -169,7 +169,9 @@ def operations_gui(full_config: dict) -> dict: ], [ sg.Button( - _t("operations_gui.unlock"), key="--UNLOCK--", size=(45, 1) + _t("operations_gui.repair_packs"), + key="--REPAIR-PACKS--", + size=(45, 1), ), sg.Button( _t("operations_gui.forget_using_retention_policy"), @@ -190,11 +192,14 @@ def operations_gui(full_config: dict) -> dict: ), ], [ + sg.Button( + _t("operations_gui.unlock"), key="--UNLOCK--", size=(45, 1) + ), sg.Button( _t("operations_gui.stats"), key="--STATS--", size=(45, 1), - ) + ), ], [sg.Button(_t("generic.quit"), key="--EXIT--")], ], @@ -259,6 +264,7 @@ def operations_gui(full_config: dict) -> dict: "--QUICK-CHECK--", "--FULL-CHECK--", "--REPAIR-INDEX--", + "--REPAIR-PACKS--", "--REPAIR-SNAPSHOTS--", "--UNLOCK--", "--FORGET--", @@ -302,6 +308,16 @@ def operations_gui(full_config: dict) -> dict: operation = "repair" op_args = {"subject": "index"} gui_msg = _t("operations_gui.repair_index") + if event == "--REPAIR-PACKS--": + operation = "repair" + pack_ids = sg.popup_get_text( + _t("operations_gui.repair_packs"), keep_on_top=True + ) + op_args = { + "subject": "packs", + "pack_ids": pack_ids, + } + gui_msg = _t("operations_gui.repair_pack") if event == "--REPAIR-SNAPSHOTS--": operation = "repair" op_args = {"subject": "snapshots"} @@ -331,6 +347,7 @@ def operations_gui(full_config: dict) -> dict: ) else: logger.error(f"Bogus operation: {operation}") + sg.popup_error(f"Bogus operation: {operation}", keep_on_top=True) event = "---STATE-UPDATE---" if event == "---STATE-UPDATE---": diff --git a/npbackup/restic_wrapper/__init__.py b/npbackup/restic_wrapper/__init__.py index b394b6a..e0ddbce 100644 --- a/npbackup/restic_wrapper/__init__.py +++ b/npbackup/restic_wrapper/__init__.py @@ -1075,17 +1075,19 @@ class ResticRunner: return self.convert_to_json_output(result, output, msg=msg, **kwargs) @check_if_init - def repair(self, subject: str) -> Union[bool, str, dict]: + def repair(self, subject: str, pack_ids) -> Union[bool, str, dict]: """ Check current repo status """ kwargs = locals() kwargs.pop("self") - if subject not in ["index", "snapshots"]: + if subject not in ["index", "packs", "snapshots"]: self.write_logs(f"Bogus repair order given: {subject}", level="error") return False cmd = f"repair {subject}" + if pack_ids: + cmd += f" {pack_ids}" result, output = self.executor(cmd) if result: msg = f"Repo successfully repaired:\n{output}" diff --git a/npbackup/translations/operations_gui.en.yml b/npbackup/translations/operations_gui.en.yml index 0e30703..f012e29 100644 --- a/npbackup/translations/operations_gui.en.yml +++ b/npbackup/translations/operations_gui.en.yml @@ -3,6 +3,8 @@ en: quick_check: Quick repo check full_check: Full repo check repair_index: Repair repo index + repair_packs: Repair repo packs + pack_ids: Pack IDs repair_snapshots: Repair repo snapshots unlock: Unlock repo forget_using_retention_policy: Forget using retention polic diff --git a/npbackup/translations/operations_gui.fr.yml b/npbackup/translations/operations_gui.fr.yml index f6fa1b2..68ef71c 100644 --- a/npbackup/translations/operations_gui.fr.yml +++ b/npbackup/translations/operations_gui.fr.yml @@ -3,6 +3,8 @@ fr: quick_check: Vérification rapide dépot full_check: Vérification complète dépot repair_index: Réparer les index du dépot + repair_packs: Réparer les blocs du dépot + pack_ids: Identifiants de blocs repair_snapshots: Réparer les instantanés du dépot unlock: Déblocage de dépot forget_using_retention_policy: Oublier les instantanés en utilisant la stratégie de rétention