prole/knoe/core/ops/openbao.py
chrisfu c94c62e1bb Harden prod deploy namespace/context routing and vault password handling
- persist and load DB master password via Ansible Vault bootstrap flow

- enforce knoe-system service namespace and explicit app/db kubecontext targeting

- improve OpenBao/CNPG deploy reliability and logging; add retries/readiness diagnostics

- tighten reset/delete cluster behavior and expand installer/deploy pipeline test coverage

Co-authored-by: Junie <junie@jetbrains.com>
2026-04-10 00:43:07 -07:00

251 lines
7.0 KiB
Python

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 _resource_namespace(namespace: str | None, env: dict | None) -> str:
if env:
explicit = str(env.get("OPENBAO_NAMESPACE") or "").strip()
if explicit:
return explicit
return _namespace(namespace, env, default="default")
def _manifest_files(mode: str, project_root: str | Path, include_kerberos: bool) -> list[Path]:
root = Path(project_root)
if mode == "k3s":
files = [
_manifest_path(root, "k8s", "prole", "openbao-service.yaml"),
_manifest_path(root, "k8s", "prole", "openbao-statefulset.yaml"),
]
else:
files = [_manifest_path(root, "k8s", "openbao", "deployment.yaml")]
if include_kerberos:
files.append(_manifest_path(root, "k8s", "openbao", "kerberos-configmap.yaml"))
return files
def _apply(
*,
namespace: str,
mode: str,
env: dict | None,
project_root: str | Path,
log: _LogFn | None,
include_kerberos_configmap: bool,
) -> None:
_ensure_namespace(namespace, env)
for manifest in _manifest_files(mode, project_root, include_kerberos_configmap):
if not manifest.exists():
continue
if manifest.name == "kerberos-configmap.yaml":
_ensure_namespace("knoe-system", env)
_log(log, f"[OPENBAO] Applying {manifest}")
try:
_kubectl(
["-n", namespace, "apply", "-f", str(manifest)],
env=env,
timeout=300,
check=True,
)
except RuntimeError as exc:
msg = str(exc)
if "does not match the namespace" not in msg:
raise
_log(
log,
"[OPENBAO] Namespace mismatch in manifest metadata; retrying apply without forced namespace.",
)
_kubectl(
["apply", "-f", str(manifest)],
env=env,
timeout=300,
check=True,
)
if mode == "k3s" or _exists("statefulset", "openbao", namespace, env=env):
_wait_rollout("statefulset", "openbao", namespace, env=env)
else:
_wait_rollout("deployment", "openbao", namespace, env=env)
def initialize(
*,
namespace: str | None = None,
env: dict | None = None,
project_root: str | Path = ".",
log: _LogFn | None = None,
mode: str | None = None,
include_kerberos_configmap: bool = True,
) -> None:
update(
namespace=namespace,
env=env,
project_root=project_root,
log=log,
mode=mode,
include_kerberos_configmap=include_kerberos_configmap,
)
def start(
*,
namespace: str | None = None,
env: dict | None = None,
project_root: str | Path = ".",
log: _LogFn | None = None,
mode: str | None = None,
include_kerberos_configmap: bool = True,
) -> None:
update(
namespace=namespace,
env=env,
project_root=project_root,
log=log,
mode=mode,
include_kerberos_configmap=include_kerberos_configmap,
)
def update(
*,
namespace: str | None = None,
env: dict | None = None,
project_root: str | Path = ".",
log: _LogFn | None = None,
mode: str | None = None,
include_kerberos_configmap: bool = True,
) -> None:
effective_mode = _detect_mode(mode, env)
target_ns = _resource_namespace(namespace, env)
_apply(
namespace=target_ns,
mode=effective_mode,
env=env,
project_root=project_root,
log=log,
include_kerberos_configmap=include_kerberos_configmap,
)
def stop(
*,
namespace: str | None = None,
env: dict | None = None,
log: _LogFn | None = None,
) -> None:
target_ns = _resource_namespace(namespace, env)
if _exists("statefulset", "openbao", target_ns, env=env):
_log(log, f"[OPENBAO] Scaling statefulset/openbao to 0 in namespace {target_ns}")
_kubectl(
[
"-n",
target_ns,
"scale",
"statefulset/openbao",
"--replicas=0",
],
env=env,
timeout=90,
check=True,
)
return
if _exists("deployment", "openbao", target_ns, env=env):
_log(log, f"[OPENBAO] Scaling deployment/openbao to 0 in namespace {target_ns}")
_kubectl(
[
"-n",
target_ns,
"scale",
"deployment/openbao",
"--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 = _resource_namespace(namespace, env)
if _exists("statefulset", "openbao", target_ns, env=env):
_log(log, f"[OPENBAO] Restarting statefulset/openbao in namespace {target_ns}")
_kubectl(
["-n", target_ns, "rollout", "restart", "statefulset/openbao"],
env=env,
timeout=120,
check=True,
)
_wait_rollout("statefulset", "openbao", target_ns, env=env)
return
if _exists("deployment", "openbao", target_ns, env=env):
_log(log, f"[OPENBAO] Restarting deployment/openbao in namespace {target_ns}")
_kubectl(
["-n", target_ns, "rollout", "restart", "deployment/openbao"],
env=env,
timeout=120,
check=True,
)
_wait_rollout("deployment", "openbao", target_ns, env=env)
def status(
*,
namespace: str | None = None,
env: dict | None = None,
mode: str | None = None,
) -> bool:
target_ns = _resource_namespace(namespace, env)
effective_mode = _detect_mode(mode, env)
ok = True
if effective_mode == "k3s" or _exists("statefulset", "openbao", target_ns, env=env):
sts = _kubectl(
[
"-n",
target_ns,
"get",
"statefulset",
"openbao",
"-o",
"jsonpath={.status.readyReplicas}",
],
env=env,
timeout=20,
)
ok = ok and sts.returncode == 0 and (sts.stdout or "0").strip() not in {"", "0"}
else:
dep = _kubectl(
[
"-n",
target_ns,
"get",
"deployment",
"openbao",
"-o",
"jsonpath={.status.readyReplicas}",
],
env=env,
timeout=20,
)
ok = ok and dep.returncode == 0 and (dep.stdout or "0").strip() not in {"", "0"}
_kubectl(["-n", target_ns, "get", "svc", "openbao"], env=env, timeout=20)
return _to_bool(ok)