add todos
This commit is contained in:
+19
-3
@@ -9,7 +9,7 @@ from pathlib import Path
|
|||||||
from re import search
|
from re import search
|
||||||
from subprocess import PIPE, Popen, call, check_output
|
from subprocess import PIPE, Popen, call, check_output
|
||||||
from sys import exit
|
from sys import exit
|
||||||
from typing import Optional
|
from typing import Optional # TODO replace with pipe notation
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
import config
|
import config
|
||||||
@@ -42,6 +42,10 @@ def main():
|
|||||||
manager.backup()
|
manager.backup()
|
||||||
|
|
||||||
|
|
||||||
|
# TODO tests
|
||||||
|
# TODO docstrings
|
||||||
|
# TODO first backup
|
||||||
|
|
||||||
class Manager:
|
class Manager:
|
||||||
def __init__(self, local_pool: Pool, external_pool: ExternalPool):
|
def __init__(self, local_pool: Pool, external_pool: ExternalPool):
|
||||||
self._local_pool = local_pool
|
self._local_pool = local_pool
|
||||||
@@ -92,6 +96,7 @@ class Manager:
|
|||||||
]
|
]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
# TODO make function
|
||||||
def _get_regex_matching_backup_tags():
|
def _get_regex_matching_backup_tags():
|
||||||
return "@" + ".*".join([config.snapshot_tag, config.snapshot_interval])
|
return "@" + ".*".join([config.snapshot_tag, config.snapshot_interval])
|
||||||
|
|
||||||
@@ -230,6 +235,8 @@ class ZFS:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def destroy(full_name, *, recursive=False):
|
def destroy(full_name, *, recursive=False):
|
||||||
|
# TODO condition must be "begins with"
|
||||||
|
# or better argument should be a ZFSPath
|
||||||
if config.local_pool_to_backup in full_name:
|
if config.local_pool_to_backup in full_name:
|
||||||
raise Exception(DELETE_IN_LOCAL_POOL)
|
raise Exception(DELETE_IN_LOCAL_POOL)
|
||||||
cmdline = [config.ZFS, "destroy"]
|
cmdline = [config.ZFS, "destroy"]
|
||||||
@@ -260,8 +267,10 @@ class ZFS:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def scrub(pool: str, *, wait_for_finish=True) -> None:
|
def scrub(pool: str, *, wait_for_finish=True) -> None:
|
||||||
|
# TODO: check if scrub already in progress
|
||||||
run_command([config.ZPOOL, "scrub", pool])
|
run_command([config.ZPOOL, "scrub", pool])
|
||||||
if wait_for_finish:
|
if wait_for_finish:
|
||||||
|
# TODO make Ctrl-c interrupt this
|
||||||
run_command([config.ZPOOL, "wait", "-t", "scrub", pool])
|
run_command([config.ZPOOL, "wait", "-t", "scrub", pool])
|
||||||
|
|
||||||
|
|
||||||
@@ -285,6 +294,7 @@ class Disk:
|
|||||||
for item in MAPPER_PATH.iterdir():
|
for item in MAPPER_PATH.iterdir():
|
||||||
if self._mapper_entry == item.name:
|
if self._mapper_entry == item.name:
|
||||||
print(MAPPER_ENTRY_ALREADY_EXISTS, self._mapper_entry)
|
print(MAPPER_ENTRY_ALREADY_EXISTS, self._mapper_entry)
|
||||||
|
# TODO exit code constants
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -298,6 +308,7 @@ class Disk:
|
|||||||
def encrypt(self):
|
def encrypt(self):
|
||||||
if not self._decrypted:
|
if not self._decrypted:
|
||||||
raise ValueError(NOT_DECRYPTED, self._name)
|
raise ValueError(NOT_DECRYPTED, self._name)
|
||||||
|
# TODO use run instead?
|
||||||
get_output_of_command([config.CRYPTSETUP, "close", self._name])
|
get_output_of_command([config.CRYPTSETUP, "close", self._name])
|
||||||
self._decrypted = False
|
self._decrypted = False
|
||||||
|
|
||||||
@@ -330,14 +341,14 @@ class ExternalPool(Pool):
|
|||||||
if self._imported:
|
if self._imported:
|
||||||
raise ValueError(ALREADY_IMPORTED, self.name)
|
raise ValueError(ALREADY_IMPORTED, self.name)
|
||||||
self._disk.decrypt()
|
self._disk.decrypt()
|
||||||
self._import_from_directory(MAPPER_PATH)
|
self._import_from_directory(MAPPER_PATH) # TODO inline?
|
||||||
self._imported = True
|
self._imported = True
|
||||||
|
|
||||||
def export(self) -> None:
|
def export(self) -> None:
|
||||||
if not self._imported:
|
if not self._imported:
|
||||||
raise ValueError(NOT_IMPORTED, self.name)
|
raise ValueError(NOT_IMPORTED, self.name)
|
||||||
self._export_pool()
|
self._export_pool()
|
||||||
self._disk.encrypt()
|
self._disk.encrypt() # TODO inline?
|
||||||
self._imported = False
|
self._imported = False
|
||||||
print(f"Exported {self.name}. Disk {self._disk.uuid} can be removed.")
|
print(f"Exported {self.name}. Disk {self._disk.uuid} can be removed.")
|
||||||
|
|
||||||
@@ -345,6 +356,7 @@ class ExternalPool(Pool):
|
|||||||
ZFS.import_pool_from_directory(self._name, directory)
|
ZFS.import_pool_from_directory(self._name, directory)
|
||||||
|
|
||||||
def _export_pool(self) -> None:
|
def _export_pool(self) -> None:
|
||||||
|
# TODO cancel scrub if necessary
|
||||||
ZFS.export_pool(self._name)
|
ZFS.export_pool(self._name)
|
||||||
|
|
||||||
def scrub(self) -> None:
|
def scrub(self) -> None:
|
||||||
@@ -371,6 +383,7 @@ class ExternalPool(Pool):
|
|||||||
# return [d for d in self.datasets if d.qualified_name not in do_not_backup_correct_name]
|
# return [d for d in self.datasets if d.qualified_name not in do_not_backup_correct_name]
|
||||||
|
|
||||||
def clean_old_snapshots(self):
|
def clean_old_snapshots(self):
|
||||||
|
print("Cleaning old snapshots")
|
||||||
for dataset in self.datasets:
|
for dataset in self.datasets:
|
||||||
dataset.clean_old_snapshots()
|
dataset.clean_old_snapshots()
|
||||||
|
|
||||||
@@ -410,10 +423,12 @@ class Dataset:
|
|||||||
self._clean_old_snapshots_for_interval(interval, number)
|
self._clean_old_snapshots_for_interval(interval, number)
|
||||||
|
|
||||||
def _clean_old_snapshots_for_interval(self, interval: str, max_count: int):
|
def _clean_old_snapshots_for_interval(self, interval: str, max_count: int):
|
||||||
|
# TODO this is somewhat similar to the regex method in Manager
|
||||||
regex = ".*".join(["", config.snapshot_tag, interval, ""])
|
regex = ".*".join(["", config.snapshot_tag, interval, ""])
|
||||||
snapshots = [
|
snapshots = [
|
||||||
snapshot for snapshot in self.snapshots if snapshot.matches_regex(regex)
|
snapshot for snapshot in self.snapshots if snapshot.matches_regex(regex)
|
||||||
]
|
]
|
||||||
|
# TODO function _get_n_oldest_snapshots
|
||||||
if len(snapshots) > max_count:
|
if len(snapshots) > max_count:
|
||||||
snapshots.sort()
|
snapshots.sort()
|
||||||
for snap in snapshots[:-max_count]:
|
for snap in snapshots[:-max_count]:
|
||||||
@@ -453,6 +468,7 @@ class Snapshot:
|
|||||||
return Dataset(self._path.dataset)
|
return Dataset(self._path.dataset)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO class CommandRunner
|
||||||
def run_command(cmdline: list[str]):
|
def run_command(cmdline: list[str]):
|
||||||
call(cmdline)
|
call(cmdline)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user