"""ZFS operations for a site's web dataset.""" from __future__ import annotations from datetime import datetime from .config import Config, Site from .runner import Runner def web_dataset(cfg: Config, site: Site) -> str: return f"{cfg.pool}/customers/{site.customer}/{site.site}/web" def customer_dataset(cfg: Config, customer: str) -> str: return f"{cfg.pool}/customers/{customer}" def exists(runner: Runner, dataset: str) -> bool: if runner.dry_run: return False out = runner.run(["zfs", "list", "-H", "-o", "name", dataset], check=False, capture=True) return dataset in out.split() def create_web(runner: Runner, cfg: Config, site: Site) -> str: ds = web_dataset(cfg, site) if not exists(runner, ds): # -p creates the customer/site parent datasets too (root-owned, 755 — # suitable as the SFTP chroot). The web child is chowned by the sftp step. runner.run(["zfs", "create", "-p", ds]) return ds def snapshot(runner: Runner, dataset: str, tag: str | None = None) -> str: tag = tag or "auto-" + datetime.now().strftime("%Y%m%d-%H%M%S") name = f"{dataset}@{tag}" runner.run(["zfs", "snapshot", name]) return name def destroy(runner: Runner, dataset: str, *, recursive: bool = True) -> None: cmd = ["zfs", "destroy"] if recursive: cmd.append("-r") cmd.append(dataset) runner.run(cmd)