from __future__ import annotations from pathlib import Path from ._services_common import ( _LogFn, _detect_mode, _ensure_namespace, _exists, _kubectl, _log, _manifest_path, _namespace, _to_bool, _wait_rollout, ) def _garage_namespace(namespace: str | None, env: dict | None) -> str: if env: explicit = str(env.get("GARAGE_NAMESPACE") or "").strip() if explicit: return explicit return _namespace(namespace, env, default="default") def _manifest_files(project_root: str | Path) -> list[Path]: root = Path(project_root) return [ _manifest_path(root, "k8s", "prole", "storageclass-synology-iscsi.yaml"), _manifest_path(root, "k8s", "prole", "iscsi-pvs.yaml"), _manifest_path(root, "k8s", "prole", "garage-configmap.yaml"), _manifest_path(root, "k8s", "prole", "garage-statefulset.yaml"), _manifest_path(root, "k8s", "prole", "garage-service.yaml"), ] def initialize( *, namespace: str | None = None, env: dict | None = None, project_root: str | Path = ".", log: _LogFn | None = None, mode: str | None = None, ) -> None: update(namespace=namespace, env=env, project_root=project_root, log=log, mode=mode) def start( *, namespace: str | None = None, env: dict | None = None, project_root: str | Path = ".", log: _LogFn | None = None, mode: str | None = None, ) -> None: update(namespace=namespace, env=env, project_root=project_root, log=log, mode=mode) def update( *, namespace: str | None = None, env: dict | None = None, project_root: str | Path = ".", log: _LogFn | None = None, mode: str | None = None, ) -> None: _detect_mode(mode, env) # mode kept for API parity target_ns = _garage_namespace(namespace, env) _ensure_namespace(target_ns, env) for manifest in _manifest_files(project_root): if not manifest.exists(): continue _log(log, f"[GARAGE] Applying {manifest}") _kubectl(["apply", "-f", str(manifest)], env=env, timeout=240, check=True) if _exists("statefulset", "garage", target_ns, env=env): _wait_rollout("statefulset", "garage", target_ns, env=env) def stop( *, namespace: str | None = None, env: dict | None = None, log: _LogFn | None = None, ) -> None: target_ns = _garage_namespace(namespace, env) if _exists("statefulset", "garage", target_ns, env=env): _log(log, f"[GARAGE] Scaling statefulset/garage to 0 in namespace {target_ns}") _kubectl( ["-n", target_ns, "scale", "statefulset/garage", "--replicas=0"], env=env, timeout=90, check=True, ) def restart( *, namespace: str | None = None, env: dict | None = None, log: _LogFn | None = None, ) -> None: target_ns = _garage_namespace(namespace, env) if _exists("statefulset", "garage", target_ns, env=env): _log(log, f"[GARAGE] Restarting statefulset/garage in namespace {target_ns}") _kubectl( ["-n", target_ns, "rollout", "restart", "statefulset/garage"], env=env, timeout=120, check=True, ) _wait_rollout("statefulset", "garage", target_ns, env=env) def status( *, namespace: str | None = None, env: dict | None = None, ) -> bool: target_ns = _garage_namespace(namespace, env) sts = _kubectl( ["-n", target_ns, "get", "statefulset", "garage", "-o", "jsonpath={.status.readyReplicas}"], env=env, timeout=20, ) svc = _kubectl(["-n", target_ns, "get", "svc", "garage"], env=env, timeout=20) return _to_bool( sts.returncode == 0 and (sts.stdout or "0").strip() not in {"", "0"} and svc.returncode == 0 )