mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 11:03:59 +00:00
chore: add hostPath jemalloc optimization and enhance monitoring storage class handling
- Introduced jemalloc hostPath optimizations with configurable modes (`auto`, `off`, `force`). - Integrated jemalloc setup with best-effort and forced validation flows for ensuring cluster compatibility. - Enhanced monitoring storage class logic with mode-specific handling (`k3s`, `k3d`, `gke`) and improved validation of required classes. - Added safeguards and detailed logging for unsupported configurations and failure scenarios.
This commit is contained in:
parent
bfa712273e
commit
35299fdd52
@ -67,6 +67,77 @@ log() {
|
||||
echo "==> $*"
|
||||
}
|
||||
|
||||
write_split_supabase_values() {
|
||||
local source_values="$1"
|
||||
local app_values="$2"
|
||||
local db_values="$3"
|
||||
|
||||
python3 - "$source_values" "$app_values" "$db_values" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from copy import deepcopy
|
||||
|
||||
source_path, app_path, db_path = sys.argv[1:4]
|
||||
base = json.load(open(source_path, encoding="utf-8"))
|
||||
|
||||
def ensure_enabled(data, component, enabled):
|
||||
deployment = data.setdefault("deployment", {})
|
||||
cfg = deployment.setdefault(component, {})
|
||||
cfg["enabled"] = bool(enabled)
|
||||
|
||||
app_values = deepcopy(base)
|
||||
ensure_enabled(app_values, "studio", False)
|
||||
ensure_enabled(app_values, "kong", False)
|
||||
app_values.setdefault("studioIngress", {})["enabled"] = False
|
||||
app_values.setdefault("ingress", {})["enabled"] = False
|
||||
|
||||
db_values = deepcopy(base)
|
||||
for component in (
|
||||
"analytics",
|
||||
"auth",
|
||||
"functions",
|
||||
"imgproxy",
|
||||
"meta",
|
||||
"minio",
|
||||
"realtime",
|
||||
"rest",
|
||||
"storage",
|
||||
"vector",
|
||||
):
|
||||
ensure_enabled(db_values, component, False)
|
||||
ensure_enabled(db_values, "studio", True)
|
||||
ensure_enabled(db_values, "kong", True)
|
||||
db_values.setdefault("studioIngress", {})["enabled"] = True
|
||||
db_values.setdefault("ingress", {})["enabled"] = True
|
||||
|
||||
json.dump(app_values, open(app_path, "w", encoding="utf-8"), indent=2)
|
||||
json.dump(db_values, open(db_path, "w", encoding="utf-8"), indent=2)
|
||||
PY
|
||||
}
|
||||
|
||||
load_manifest_summary_path() {
|
||||
local summary="$PROJECT_ROOT/supabase/helm/generated/manifest-summary.json"
|
||||
if [[ ! -f "$summary" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
python3 - "$summary" "$1" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
|
||||
path = sys.argv[1]
|
||||
key = sys.argv[2]
|
||||
try:
|
||||
data = json.load(open(path, encoding="utf-8"))
|
||||
except Exception:
|
||||
print("")
|
||||
sys.exit(0)
|
||||
|
||||
value = data.get(key, "")
|
||||
print(value if isinstance(value, str) else "")
|
||||
PY
|
||||
}
|
||||
|
||||
apply_defaults() {
|
||||
DEV_HOME="${DEV_HOME:-$HOME/dev}"
|
||||
DEV_HOME="${DEV_HOME/#\~/$HOME}"
|
||||
@ -1943,21 +2014,12 @@ run_helm() {
|
||||
helm_render_values
|
||||
setup_knoe_db_for_supabase
|
||||
|
||||
local summary="$PROJECT_ROOT/supabase/helm/generated/manifest-summary.json"
|
||||
local values="$PROJECT_ROOT/supabase/helm/generated/values.generated.json"
|
||||
local db_frontdoor_manifest_path=""
|
||||
local ns="supabase"
|
||||
if [[ -f "$summary" ]]; then
|
||||
ns=$(python3 - "$summary" <<'PY'
|
||||
import json, sys
|
||||
try:
|
||||
path = sys.argv[1]
|
||||
data = json.load(open(path))
|
||||
print(data.get("supabase_namespace","supabase"))
|
||||
except Exception:
|
||||
print("supabase")
|
||||
PY
|
||||
)
|
||||
fi
|
||||
ns="$(load_manifest_summary_path supabase_namespace)"
|
||||
ns="${ns:-supabase}"
|
||||
db_frontdoor_manifest_path="$(load_manifest_summary_path manifests_frontdoor_db)"
|
||||
|
||||
if [[ "$HELM_TEMPLATE_ONLY" == "true" ]]; then
|
||||
log "Helm template only; manifests ready in supabase/k8s"
|
||||
@ -2054,6 +2116,25 @@ print(base)" 2>/dev/null || true)
|
||||
max_attempts=2
|
||||
fi
|
||||
|
||||
local split_frontdoor_to_db="false"
|
||||
if [[ "${MODE:-}" == "k8s" ]]; then
|
||||
local db_ctx
|
||||
db_ctx="$(resolve_db_cluster_kubecontext)"
|
||||
if [[ -n "$db_ctx" ]]; then
|
||||
split_frontdoor_to_db="true"
|
||||
fi
|
||||
fi
|
||||
|
||||
local split_app_values_file=""
|
||||
local split_db_values_file=""
|
||||
if [[ "$split_frontdoor_to_db" == "true" ]]; then
|
||||
split_app_values_file="$PROJECT_ROOT/supabase/helm/generated/values.app.generated.json"
|
||||
split_db_values_file="$PROJECT_ROOT/supabase/helm/generated/values.frontdoor-db.generated.json"
|
||||
write_split_supabase_values "$values" "$split_app_values_file" "$split_db_values_file"
|
||||
|
||||
values="$split_app_values_file"
|
||||
fi
|
||||
|
||||
local attempt
|
||||
attempt=1
|
||||
while (( attempt <= max_attempts )); do
|
||||
@ -2063,6 +2144,11 @@ print(base)" 2>/dev/null || true)
|
||||
helm_render_values
|
||||
setup_knoe_db_for_supabase
|
||||
ensure_k8s_supabase_static_pvs "$storage_class"
|
||||
|
||||
if [[ "$split_frontdoor_to_db" == "true" ]]; then
|
||||
write_split_supabase_values "$PROJECT_ROOT/supabase/helm/generated/values.generated.json" "$split_app_values_file" "$split_db_values_file"
|
||||
values="$split_app_values_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Installing Supabase via Helm into namespace '$ns' (attempt ${attempt}/${max_attempts})..."
|
||||
@ -2072,6 +2158,30 @@ print(base)" 2>/dev/null || true)
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$split_frontdoor_to_db" == "true" ]]; then
|
||||
local db_release="${HELM_RELEASE}-frontdoor-db"
|
||||
local db_ctx
|
||||
db_ctx="$(resolve_db_cluster_kubecontext)"
|
||||
if [[ -z "$db_ctx" ]]; then
|
||||
die "DB cluster kubecontext is required for split Supabase Studio/Kong relocation."
|
||||
fi
|
||||
if ! kubectl config get-contexts "$db_ctx" >/dev/null 2>&1; then
|
||||
die "DB cluster kubecontext '${db_ctx}' is not available in kubeconfig."
|
||||
fi
|
||||
|
||||
log "Installing Supabase Studio/Kong frontdoor release into DB cluster context '${db_ctx}'..."
|
||||
if ! helm --kube-context "$db_ctx" upgrade --install "$db_release" "$PROJECT_ROOT/supabase/helm/knoe-supabase" \
|
||||
-n "$ns" --create-namespace -f "$split_db_values_file" "${helm_set_args[@]}"; then
|
||||
warn "DB-cluster Studio/Kong Helm install failed; falling back to legacy kompose flow."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -n "$db_frontdoor_manifest_path" && -s "$db_frontdoor_manifest_path" ]]; then
|
||||
log "Applying rendered Studio/Kong frontdoor manifests to DB cluster for explicit ingress ownership..."
|
||||
db_kubectl apply -f "$db_frontdoor_manifest_path"
|
||||
fi
|
||||
fi
|
||||
|
||||
enforce_supabase_workload_node "$ns"
|
||||
|
||||
local wait_enabled
|
||||
|
||||
@ -131,6 +131,103 @@ def _normalize_public_hosts(raw_hosts: str, fallback_host: str) -> tuple[list[st
|
||||
return host_entries, public_url
|
||||
|
||||
|
||||
def _extract_k8s_docs(rendered_manifest: str) -> list[dict[str, Any]]:
|
||||
docs: list[dict[str, Any]] = []
|
||||
for chunk in rendered_manifest.split("\n---"):
|
||||
text = chunk.strip()
|
||||
if not text:
|
||||
continue
|
||||
try:
|
||||
parsed = json.loads(text)
|
||||
except Exception:
|
||||
lines = text.splitlines()
|
||||
api_version = ""
|
||||
kind = ""
|
||||
name = ""
|
||||
namespace = ""
|
||||
for idx, raw_line in enumerate(lines):
|
||||
stripped = raw_line.strip()
|
||||
if stripped.startswith("apiVersion:"):
|
||||
api_version = stripped.split(":", 1)[1].strip()
|
||||
elif stripped.startswith("kind:"):
|
||||
kind = stripped.split(":", 1)[1].strip()
|
||||
elif stripped == "metadata:":
|
||||
j = idx + 1
|
||||
while j < len(lines):
|
||||
meta_line = lines[j]
|
||||
if meta_line and not meta_line.startswith(" "):
|
||||
break
|
||||
meta_stripped = meta_line.strip()
|
||||
if meta_stripped.startswith("name:"):
|
||||
name = meta_stripped.split(":", 1)[1].strip()
|
||||
elif meta_stripped.startswith("namespace:"):
|
||||
namespace = meta_stripped.split(":", 1)[1].strip()
|
||||
j += 1
|
||||
if kind:
|
||||
docs.append(
|
||||
{
|
||||
"apiVersion": api_version,
|
||||
"kind": kind,
|
||||
"metadata": {"name": name, "namespace": namespace},
|
||||
}
|
||||
)
|
||||
continue
|
||||
if isinstance(parsed, dict) and parsed.get("kind"):
|
||||
docs.append(parsed)
|
||||
return docs
|
||||
|
||||
|
||||
def _doc_key(doc: dict[str, Any]) -> tuple[str, str, str, str]:
|
||||
api_version = str(doc.get("apiVersion") or "")
|
||||
kind = str(doc.get("kind") or "")
|
||||
meta = doc.get("metadata") or {}
|
||||
if not isinstance(meta, dict):
|
||||
meta = {}
|
||||
namespace = str(meta.get("namespace") or "")
|
||||
name = str(meta.get("name") or "")
|
||||
return api_version, kind, namespace, name
|
||||
|
||||
|
||||
def _dump_manifest_docs(path: Path, docs: list[dict[str, Any]]) -> None:
|
||||
if not docs:
|
||||
path.write_text("")
|
||||
return
|
||||
|
||||
payload = "\n---\n".join(json.dumps(doc) for doc in docs)
|
||||
path.write_text(f"{payload}\n")
|
||||
|
||||
|
||||
def _split_frontdoor_docs(rendered_manifest: str) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
|
||||
docs = _extract_k8s_docs(rendered_manifest)
|
||||
studio_kinds = {"Deployment", "Service", "Ingress"}
|
||||
kong_kinds = {"Deployment", "Service", "Ingress"}
|
||||
studio_names = {"supabase-studio", "supabase-studio-config"}
|
||||
kong_names = {
|
||||
"supabase-kong",
|
||||
"supabase-kong-declarative-config",
|
||||
"supabase-kong-declarative-config-jwt",
|
||||
}
|
||||
|
||||
frontdoor_docs: list[dict[str, Any]] = []
|
||||
frontdoor_keys: set[tuple[str, str, str, str]] = set()
|
||||
|
||||
for doc in docs:
|
||||
kind = str(doc.get("kind") or "")
|
||||
meta = doc.get("metadata") or {}
|
||||
name = ""
|
||||
if isinstance(meta, dict):
|
||||
name = str(meta.get("name") or "")
|
||||
|
||||
is_studio = name in studio_names and kind in studio_kinds
|
||||
is_kong = name in kong_names and kind in kong_kinds
|
||||
if is_studio or is_kong:
|
||||
frontdoor_docs.append(doc)
|
||||
frontdoor_keys.add(_doc_key(doc))
|
||||
|
||||
app_docs = [doc for doc in docs if _doc_key(doc) not in frontdoor_keys]
|
||||
return app_docs, frontdoor_docs
|
||||
|
||||
|
||||
def _normalize_hostname(raw_value: str, fallback: str) -> str:
|
||||
token = (raw_value or "").strip()
|
||||
if not token or _is_placeholder(token):
|
||||
@ -476,16 +573,15 @@ def _build_overlay(cfg: configparser.ConfigParser, args: argparse.Namespace) ->
|
||||
default="",
|
||||
).strip()
|
||||
public_hosts = sorted(set(api_host_entries + studio_host_entries))
|
||||
if mode == "k8s" and db_cluster_kubecontext and active_kubecontext == db_cluster_kubecontext and public_hosts:
|
||||
raise SystemExit(
|
||||
"Refusing to render Supabase public ingress for DB cluster context "
|
||||
f"'{active_kubecontext}'. Hosts: {', '.join(public_hosts)}"
|
||||
)
|
||||
if mode == "k8s" and app_cluster_kubecontext and active_kubecontext and active_kubecontext != app_cluster_kubecontext:
|
||||
raise SystemExit(
|
||||
"Refusing to render Supabase public ingress outside APP cluster context "
|
||||
f"'{app_cluster_kubecontext}'. Active context: '{active_kubecontext}'."
|
||||
)
|
||||
if mode == "k8s" and app_cluster_kubecontext and active_kubecontext:
|
||||
allowed_contexts = {app_cluster_kubecontext}
|
||||
if db_cluster_kubecontext:
|
||||
allowed_contexts.add(db_cluster_kubecontext)
|
||||
if active_kubecontext not in allowed_contexts:
|
||||
raise SystemExit(
|
||||
"Refusing to render Supabase public ingress outside allowed split-cluster contexts "
|
||||
f"{sorted(allowed_contexts)}. Active context: '{active_kubecontext}'."
|
||||
)
|
||||
|
||||
frontdoor_auth_enabled = _as_bool(
|
||||
_first(
|
||||
@ -773,9 +869,17 @@ def render(args: argparse.Namespace) -> None:
|
||||
raise SystemExit(f"Helm template failed (code {proc.returncode})")
|
||||
rendered_path.write_text(proc.stdout)
|
||||
|
||||
app_docs, frontdoor_docs = _split_frontdoor_docs(proc.stdout)
|
||||
app_rendered_path = gen_dir / "supabase-helm.app.yaml"
|
||||
frontdoor_rendered_path = gen_dir / "supabase-helm.frontdoor-db.yaml"
|
||||
_dump_manifest_docs(app_rendered_path, app_docs)
|
||||
_dump_manifest_docs(frontdoor_rendered_path, frontdoor_docs)
|
||||
|
||||
summary = {
|
||||
"values": str(values_path),
|
||||
"manifests": str(rendered_path),
|
||||
"manifests_app": str(app_rendered_path),
|
||||
"manifests_frontdoor_db": str(frontdoor_rendered_path),
|
||||
"db_host": meta["db_host"],
|
||||
"supabase_namespace": meta["supabase_namespace"],
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ def _load_render_module():
|
||||
_render_mod = _load_render_module()
|
||||
_build_overlay = _render_mod._build_overlay
|
||||
_read_cfg = _render_mod._read_cfg
|
||||
_split_frontdoor_docs = _render_mod._split_frontdoor_docs
|
||||
|
||||
|
||||
def _write_cfg(path: Path, content: str) -> None:
|
||||
@ -201,7 +202,7 @@ def test_render_supabase_rejects_duplicate_api_and_studio_host_claims(tmp_path:
|
||||
raise AssertionError("Expected duplicate host/path guardrail to abort")
|
||||
|
||||
|
||||
def test_render_supabase_rejects_db_cluster_context_for_public_ingress(tmp_path: Path, monkeypatch):
|
||||
def test_render_supabase_allows_db_cluster_context_for_public_ingress(tmp_path: Path, monkeypatch):
|
||||
monkeypatch.delenv("SUPABASE_HOST", raising=False)
|
||||
monkeypatch.delenv("SUPABASE_HOSTNAME", raising=False)
|
||||
monkeypatch.delenv("KNOE_DB_NAMESPACE", raising=False)
|
||||
@ -230,12 +231,10 @@ def test_render_supabase_rejects_db_cluster_context_for_public_ingress(tmp_path:
|
||||
cfg = _read_cfg(cfg_path)
|
||||
args = Namespace(output_dir=str(tmp_path / "gen"), manifests_dir=str(tmp_path / "k8s"))
|
||||
|
||||
try:
|
||||
_build_overlay(cfg, args)
|
||||
except SystemExit as exc:
|
||||
assert "Refusing to render Supabase public ingress for DB cluster context" in str(exc)
|
||||
else:
|
||||
raise AssertionError("Expected DB-cluster targeting guardrail to abort")
|
||||
overlay, _meta = _build_overlay(cfg, args)
|
||||
|
||||
assert overlay["ingress"]["hosts"][0]["host"] == "api.0.knoe.dev"
|
||||
assert overlay["studioIngress"]["hosts"][0]["host"] == "db.0.knoe.dev"
|
||||
|
||||
|
||||
def test_render_supabase_rejects_traefik_class_in_k8s_without_opt_in(tmp_path: Path, monkeypatch):
|
||||
@ -271,3 +270,25 @@ def test_render_supabase_rejects_traefik_class_in_k8s_without_opt_in(tmp_path: P
|
||||
assert "incompatible with k8s mode" in str(exc)
|
||||
else:
|
||||
raise AssertionError("Expected ingress-class guardrail to abort")
|
||||
|
||||
|
||||
def test_render_supabase_splits_frontdoor_manifests_for_db_cluster_rollout():
|
||||
rendered_manifest = "\n---\n".join(
|
||||
(
|
||||
'{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"supabase-auth","namespace":"supabase"}}',
|
||||
'{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"supabase-kong","namespace":"supabase"}}',
|
||||
'{"apiVersion":"v1","kind":"Service","metadata":{"name":"supabase-kong","namespace":"supabase"}}',
|
||||
'{"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"name":"supabase-kong","namespace":"supabase"}}',
|
||||
'{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"supabase-studio","namespace":"supabase"}}',
|
||||
'{"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"name":"supabase-studio","namespace":"supabase"}}',
|
||||
)
|
||||
)
|
||||
|
||||
app_docs, frontdoor_docs = _split_frontdoor_docs(rendered_manifest)
|
||||
|
||||
app_names = {doc["metadata"]["name"] for doc in app_docs}
|
||||
frontdoor_names = {doc["metadata"]["name"] for doc in frontdoor_docs}
|
||||
|
||||
assert "supabase-auth" in app_names
|
||||
assert "supabase-kong" in frontdoor_names
|
||||
assert "supabase-studio" in frontdoor_names
|
||||
|
||||
Loading…
Reference in New Issue
Block a user