Skip to content
Snippets Groups Projects
Commit b52a43a3 authored by Radoslav Bodó's avatar Radoslav Bodó
Browse files

rwm: add prerun and postrun hooks for backups

parent 2c9f792b
No related branches found
No related tags found
No related merge requests found
Pipeline #7601 passed
......@@ -40,7 +40,8 @@ somewhere - if I only knew.*
* performing backups
* restic with S3 repository
* simple backup manager/executor
* saves bucket state during backups
* prerun and postrun shell hooks
* bucket state saving after backups
* storage management
* create, delete and list policed storage buckets
......
......@@ -437,6 +437,26 @@ class RWM:
return self.restic_cmd(cmd_args)
def _runparts(self, parts_name, parts: list) -> int:
"""run all commands in parts in shell"""
for part in parts:
logger.info("rwm _runparts %s shell command, %s", parts_name, json.dumps(part))
wrap_output(part_proc := run_command(part, shell=True))
if part_proc.returncode != 0:
logger.error("rwm _runparts failed")
return part_proc.returncode
return 0
def _prerun(self, name) -> int:
"""prerun runparts stub"""
return self._runparts("prerun", self.config["rwm_backups"][name].get("prerun", []))
def _postrun(self, name) -> int:
"""postrun runparts stub"""
return self._runparts("postrun", self.config["rwm_backups"][name].get("postrun", []))
def backup(self, name) -> int:
"""backup command"""
......@@ -445,11 +465,19 @@ class RWM:
if not self.storage_manager.storage_check_policy(bucket_name):
logger.warning("used bucket does not have expected policy")
if self._prerun(name) != 0:
logger.error("rwm _prerun failed")
return 1
wrap_output(backup_proc := self._restic_backup(name))
if backup_proc.returncode != 0:
logger.error("rwm _restic_backup failed")
return 1
if self._postrun(name) != 0:
logger.error("rwm _postrun failed")
return 1
wrap_output(forget_proc := self._restic_forget_prune())
if forget_proc.returncode != 0:
logger.error("rwm _restic_forget_prune failed")
......
......@@ -56,6 +56,18 @@ def _restic_list_snapshot_files(trwm, snapshot_id):
return [x["path"] for x in snapshot_ls if (x["struct_type"] == "node") and (x["type"] == "file")]
def test_runparts(tmpworkdir: str, motoserver: str): # pylint: disable=unused-argument
"""test runparts"""
trwm = rwm.RWM({
"rwm_s3_endpoint_url": motoserver,
"rwm_s3_access_key": "dummy",
"rwm_s3_secret_key": "dummy",
})
assert trwm._runparts("tests", ["false"]) == 1 # pylint: disable=protected-access
def test_backup(tmpworkdir: str, motoserver: str): # pylint: disable=unused-argument
"""test backup"""
......@@ -133,6 +145,36 @@ def test_backup_excludes(tmpworkdir: str, motoserver: str): # pylint: disable=u
assert "/testdatadir/var/proc/data" in snapshot_files
def test_backup_runparts(tmpworkdir: str, motoserver: str): # pylint: disable=unused-argument
"""test backup"""
trwm = rwm.RWM({
"rwm_s3_endpoint_url": motoserver,
"rwm_s3_access_key": "dummy",
"rwm_s3_secret_key": "dummy",
"rwm_restic_bucket": "restictest",
"rwm_restic_password": "dummydummydummydummy",
"rwm_backups": {
"testcfg": {
"filesdirs": ["testdatadir/"],
"prerun": ["false || true"],
"postrun": ["true || false"]
}
}
})
mock_ok = Mock(return_value=0)
mock_proc_ok = Mock(return_value=CompletedProcess(args='dummy', returncode=0))
with (
patch.object(rwm.StorageManager, "storage_check_policy", mock_ok),
patch.object(rwm.RWM, "_restic_backup", mock_proc_ok),
patch.object(rwm.RWM, "_restic_forget_prune", mock_proc_ok),
patch.object(rwm.StorageManager, "storage_save_state", mock_ok)
):
assert trwm.backup("testcfg") == 0
def test_backup_error_handling(tmpworkdir: str, motoserver: str): # pylint: disable=unused-argument
"""test backup command err cases"""
......@@ -144,22 +186,40 @@ def test_backup_error_handling(tmpworkdir: str, motoserver: str): # pylint: dis
}
mock_proc_ok = Mock(return_value=CompletedProcess(args='dummy', returncode=0))
mock_proc_fail = Mock(return_value=CompletedProcess(args='dummy', returncode=2))
mock_ok = Mock(return_value=0)
mock_fail = Mock(return_value=11)
with (
patch.object(rwm.RWM, "_prerun", mock_fail)
):
assert rwm.RWM(rwm_conf).backup("dummycfg") == 1
with (
patch.object(rwm.RWM, "_prerun", mock_ok),
patch.object(rwm.RWM, "_restic_backup", mock_proc_fail)
):
assert rwm.RWM(rwm_conf).backup("dummycfg") == 1
with (
patch.object(rwm.RWM, "_prerun", mock_ok),
patch.object(rwm.RWM, "_restic_backup", mock_proc_ok),
patch.object(rwm.RWM, "_restic_forget_prune", mock_proc_fail)
):
assert rwm.RWM(rwm_conf).backup("dummycfg") == 1
with (
patch.object(rwm.RWM, "_prerun", mock_ok),
patch.object(rwm.RWM, "_restic_backup", mock_proc_ok),
patch.object(rwm.RWM, "_restic_forget_prune", mock_proc_ok),
patch.object(rwm.RWM, "_postrun", mock_fail)
):
assert rwm.RWM(rwm_conf).backup("dummycfg") == 1
with (
patch.object(rwm.RWM, "_prerun", mock_ok),
patch.object(rwm.RWM, "_restic_backup", mock_proc_ok),
patch.object(rwm.RWM, "_restic_forget_prune", mock_proc_ok),
patch.object(rwm.RWM, "_postrun", mock_ok),
patch.object(rwm.StorageManager, "storage_save_state", mock_fail)
):
assert rwm.RWM(rwm_conf).backup("dummycfg") == 1
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment