add: docstrings in Manager
This commit is contained in:
+39
-10
@@ -48,6 +48,8 @@ def main():
|
||||
|
||||
|
||||
class Manager:
|
||||
"""Controls the overall backup process."""
|
||||
|
||||
_map_type: dict[Dataset, Dataset | None]
|
||||
|
||||
def __init__(self, local_pool: Pool, external_pool: ExternalPool):
|
||||
@@ -55,6 +57,7 @@ class Manager:
|
||||
self._external_pool = external_pool
|
||||
|
||||
def backup(self):
|
||||
"""Backup workflow."""
|
||||
self._external_pool.import_()
|
||||
try:
|
||||
self._external_pool.scrub(skip_if_recently_scrubbed=True)
|
||||
@@ -65,18 +68,26 @@ class Manager:
|
||||
self._external_pool.export()
|
||||
|
||||
def _backup_all_datasets(self):
|
||||
"""Send snapshots of local datasets to the backup pool."""
|
||||
print("Backing up datasets")
|
||||
for local_dataset, remote_dataset in self._get_dataset_backup_map().items():
|
||||
for (
|
||||
local_dataset,
|
||||
remote_dataset,
|
||||
) in self._get_user_filtered_dataset_backup_map().items():
|
||||
if remote_dataset is None:
|
||||
stream = self._send_absolute(local_dataset)
|
||||
else:
|
||||
stream = self._send_incremental(local_dataset, remote_dataset)
|
||||
ZFS.receive(stream, self._external_pool)
|
||||
|
||||
def _get_dataset_backup_map(self) -> _map_type:
|
||||
def _get_user_filtered_dataset_backup_map(self) -> _map_type:
|
||||
return self._user_confirm_new_datasets(self._get_raw_dataset_map())
|
||||
|
||||
def _user_confirm_new_datasets(self, dataset_map: _map_type) -> _map_type:
|
||||
"""For datasets that exist only locally, ask the user if he wants to back it up.
|
||||
|
||||
If he doesn't, remove it from the dict.
|
||||
"""
|
||||
return {
|
||||
local_dataset: remote_dataset
|
||||
for local_dataset, remote_dataset in dataset_map.items()
|
||||
@@ -84,6 +95,10 @@ class Manager:
|
||||
}
|
||||
|
||||
def _get_raw_dataset_map(self) -> _map_type:
|
||||
"""Return map from local to remote datasets.
|
||||
|
||||
If the local dataset has no remote match, set the remote dataset to None.
|
||||
"""
|
||||
return {
|
||||
local_dataset: self._search_matching_dataset_in_remote_pool(
|
||||
local_dataset, self._external_pool
|
||||
@@ -94,23 +109,29 @@ class Manager:
|
||||
def _send_incremental(
|
||||
self, local_dataset: Dataset, remote_dataset: Dataset
|
||||
) -> Popen:
|
||||
start_snapshot = self._get_last_common_snapshot(local_dataset, remote_dataset)
|
||||
end_snapshot = self._get_last_snapshot_with_backup_tag(local_dataset)
|
||||
"""Send incremental stream between two datasets to remote."""
|
||||
start_snapshot = self._get_newest_common_snapshot_with_backup_tags(
|
||||
local_dataset, remote_dataset
|
||||
)
|
||||
end_snapshot = self._get_newest_snapshot_with_backup_tag(local_dataset)
|
||||
stream = ZFS.send_incremental(start_snapshot, end_snapshot)
|
||||
return stream
|
||||
|
||||
def _send_absolute(self, local_dataset: Dataset) -> Popen:
|
||||
snapshot = self._get_last_snapshot_with_backup_tag(local_dataset)
|
||||
"""Send absolute stream to remote."""
|
||||
snapshot = self._get_newest_snapshot_with_backup_tag(local_dataset)
|
||||
return ZFS.send_absolute(snapshot)
|
||||
|
||||
def _get_last_snapshot_with_backup_tag(self, local_dataset):
|
||||
snapshots = self._find_snapshots_with_backup_tag(local_dataset)
|
||||
def _get_newest_snapshot_with_backup_tag(self, dataset: Dataset) -> Snapshot:
|
||||
"""From all snapshots in the dataset, get the newest one that matches the backup tags in the config."""
|
||||
snapshots = self._find_snapshots_with_backup_tag(dataset)
|
||||
snapshots.sort()
|
||||
end_snapshot = snapshots[-1]
|
||||
return end_snapshot
|
||||
|
||||
@property
|
||||
def _datasets_to_backup(self) -> list[Dataset]:
|
||||
"""Return local datasets to consider for a backup."""
|
||||
return [
|
||||
dataset
|
||||
for dataset in self._local_pool.datasets
|
||||
@@ -119,6 +140,7 @@ class Manager:
|
||||
|
||||
@staticmethod
|
||||
def _find_snapshots_with_backup_tag(dataset: Dataset) -> list[Snapshot]:
|
||||
"""Find snapshots of a dataset that carry the backup tags."""
|
||||
regex = _get_regex_matching_snapshots_with_tags(
|
||||
[config.snapshot_tag, config.snapshot_interval]
|
||||
)
|
||||
@@ -130,15 +152,22 @@ class Manager:
|
||||
def _search_matching_dataset_in_remote_pool(
|
||||
dataset: Dataset, pool: Pool
|
||||
) -> Dataset | None:
|
||||
"""For a dataset in the local pool, get the matching dataset in the remote pool.
|
||||
|
||||
If there is no match, return None.
|
||||
"""
|
||||
dataset_to_search = dataset.replace_pool(pool.name)
|
||||
for dataset in pool.datasets:
|
||||
if dataset == dataset_to_search:
|
||||
return dataset
|
||||
|
||||
@classmethod
|
||||
def _get_last_common_snapshot(
|
||||
def _get_newest_common_snapshot_with_backup_tags(
|
||||
cls, local_dataset: Dataset, remote_dataset: Dataset
|
||||
) -> Snapshot:
|
||||
"""In a local and a remote dataset, find the newest snapshot with backup tags which exists in both datasets.
|
||||
|
||||
Return the local snapshot."""
|
||||
common_snapshots = [
|
||||
local_snap
|
||||
for local_snap in list(cls._find_snapshots_with_backup_tag(local_dataset))
|
||||
@@ -287,7 +316,7 @@ class ZPool(CommandInterface):
|
||||
cls._scrub_if_necessary(pool, skip_if_recently_scrubbed)
|
||||
if wait_for_finish:
|
||||
cls._run_command(*cls._Subcommands.wait, pool.name)
|
||||
if not cls._healthy(pool):
|
||||
if not cls._is_healthy(pool):
|
||||
raise IOError(f"Pool {pool.name} is not healthy.")
|
||||
|
||||
@classmethod
|
||||
@@ -312,7 +341,7 @@ class ZPool(CommandInterface):
|
||||
return "scrub in progress" in cls._get_pool_status_output(pool)
|
||||
|
||||
@classmethod
|
||||
def _healthy(cls, pool: Pool) -> bool:
|
||||
def _is_healthy(cls, pool: Pool) -> bool:
|
||||
return "ONLINE" in cls._get_pool_status_output(pool)
|
||||
|
||||
@classmethod
|
||||
|
||||
Reference in New Issue
Block a user