Implement ZFS dataset management and snapshot configuration
- Introduced a new `datasets.nix` file to define ZFS datasets and their properties, allowing for centralized management of dataset configurations. - Updated `default.nix` to import and enable the `zfs_manager` service, integrating it into the system configuration. - Refactored `zfs.sh` to remove dataset creation commands, delegating dataset management to the `zfs_manager` service. - Removed the legacy `snapshot_config.toml` file, as snapshot configurations are now handled within `datasets.nix`. - Modified `vars.nix` to derive mountpoint paths from `datasets.nix`, ensuring consistency across the configuration. - Created a new `zfs.nix` file to define the `zfs_manager` service and its dependencies. - Added comprehensive tests for the `zfs_manager` functionality, covering dataset creation, property management, and error handling.
This commit is contained in:
@@ -23,6 +23,7 @@ def main(config_file: Path) -> None:
|
||||
"""Main."""
|
||||
configure_logger(level="DEBUG")
|
||||
logger.info("Starting snapshot_manager")
|
||||
failures: list[str] = []
|
||||
|
||||
try:
|
||||
time_stamp = get_time_stamp()
|
||||
@@ -34,16 +35,23 @@ def main(config_file: Path) -> None:
|
||||
msg = f"{dataset.name} failed to create snapshot {time_stamp}"
|
||||
logger.error(msg)
|
||||
signal_alert(msg)
|
||||
failures.append(msg)
|
||||
continue
|
||||
count_lookup = get_count_lookup(config_file, dataset.name)
|
||||
logger.info(f"using {count_lookup} for {dataset.name}")
|
||||
get_snapshots_to_delete(dataset, count_lookup)
|
||||
failures.extend(get_snapshots_to_delete(dataset, count_lookup))
|
||||
except Exception:
|
||||
logger.exception("snapshot_manager failed")
|
||||
signal_alert("snapshot_manager failed")
|
||||
sys.exit(1)
|
||||
else:
|
||||
logger.info("snapshot_manager completed")
|
||||
|
||||
if failures:
|
||||
logger.error(f"snapshot_manager completed with {len(failures)} errors")
|
||||
for failure in failures:
|
||||
logger.error(f" {failure}")
|
||||
sys.exit(1)
|
||||
|
||||
logger.info("snapshot_manager completed")
|
||||
|
||||
|
||||
def get_count_lookup(config_file: Path, dataset_name: str) -> dict[str, int]:
|
||||
@@ -92,19 +100,29 @@ def load_config_data(config_file: Path) -> dict[str, dict[str, int]]:
|
||||
def get_snapshots_to_delete(
|
||||
dataset: Dataset,
|
||||
count_lookup: dict[str, int],
|
||||
) -> None:
|
||||
) -> list[str]:
|
||||
"""Get snapshots to delete.
|
||||
|
||||
Args:
|
||||
dataset (Dataset): the dataset
|
||||
count_lookup (dict[str, int]): the count lookup
|
||||
|
||||
Returns:
|
||||
list[str]: Snapshot deletion failures encountered while pruning.
|
||||
"""
|
||||
for retention_class in ("15_min", "hourly", "daily", "monthly"):
|
||||
count = count_lookup.get(retention_class)
|
||||
if not isinstance(count, int) or isinstance(count, bool) or count < 0:
|
||||
error = f"{retention_class} retention must be a non-negative integer, got {count!r}"
|
||||
raise ValueError(error)
|
||||
|
||||
failures: list[str] = []
|
||||
snapshots = dataset.get_snapshots()
|
||||
|
||||
logger.info(f"calculating snapshots for {dataset.name} to be deleted")
|
||||
if not snapshots:
|
||||
logger.info(f"{dataset.name} has no snapshots")
|
||||
return
|
||||
return failures
|
||||
|
||||
filters = (
|
||||
("15_min", re_compile(r"auto_\d{10}(?:15|30|45)")),
|
||||
@@ -129,6 +147,9 @@ def get_snapshots_to_delete(
|
||||
error_message = f"{dataset.name}@{snapshot} failed to delete: {error}"
|
||||
signal_alert(error_message)
|
||||
logger.error(error_message)
|
||||
failures.append(error_message)
|
||||
|
||||
return failures
|
||||
|
||||
|
||||
def get_time_stamp() -> str:
|
||||
|
||||
Reference in New Issue
Block a user