feat: k8s:// ClusterIP claim env + complete payload target_repo
Resolve llm-connect / actcore-api / edge-relay without port-forward. Include target_repo on FI and Binky complete payloads for ops UI artefacts.
This commit is contained in:
parent
6383944939
commit
94a15d67aa
7 changed files with 207 additions and 8 deletions
110
deploy/scripts/rein-aharness-claim
Executable file
110
deploy/scripts/rein-aharness-claim
Executable file
|
|
@ -0,0 +1,110 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Claim-loop launcher: load claim-loop.env and resolve k8s:// Service URLs.
|
||||
|
||||
Used as ~/bin/rein-aharness-claim on railiance01 so shell never sources JSON
|
||||
values (AGENT_HARNESS_REPO_MAP). Supports durable ClusterIP access without
|
||||
kubectl port-forward (ACTIVITY-WP-0027 / docs in activity-core).
|
||||
|
||||
Env file keys may use:
|
||||
LLM_CONNECT_URL=k8s://activity-core/llm-connect:8080
|
||||
ACTIVITY_CORE_URL=k8s://activity-core/actcore-api:8010
|
||||
STATE_HUB_URL=k8s://activity-core/actcore-statehub-edge-relay:8000
|
||||
|
||||
Resolution uses: kubectl -n <ns> get svc <name> -o jsonpath={.spec.clusterIP}
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_K8S_URL = re.compile(
|
||||
r"^k8s://(?P<ns>[a-z0-9-]+)/(?P<svc>[a-z0-9-]+)(?::(?P<port>\d+))?/?$"
|
||||
)
|
||||
|
||||
|
||||
def _load_env_file(path: Path) -> dict[str, str]:
|
||||
out: dict[str, str] = {}
|
||||
if not path.is_file():
|
||||
return out
|
||||
for line in path.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, value = line.split("=", 1)
|
||||
out[key.strip()] = value.strip()
|
||||
return out
|
||||
|
||||
|
||||
def _resolve_k8s_url(value: str) -> str:
|
||||
m = _K8S_URL.match(value.strip())
|
||||
if not m:
|
||||
return value
|
||||
ns = m.group("ns")
|
||||
svc = m.group("svc")
|
||||
port = m.group("port") or "80"
|
||||
kubeconfig = os.environ.get("KUBECONFIG", "/etc/rancher/k3s/k3s.yaml")
|
||||
cmd = [
|
||||
"kubectl",
|
||||
f"--kubeconfig={kubeconfig}",
|
||||
"-n",
|
||||
ns,
|
||||
"get",
|
||||
"svc",
|
||||
svc,
|
||||
"-o",
|
||||
"jsonpath={.spec.clusterIP}",
|
||||
]
|
||||
try:
|
||||
ip = subprocess.check_output(cmd, text=True, timeout=30).strip()
|
||||
except (subprocess.CalledProcessError, FileNotFoundError, subprocess.TimeoutExpired) as exc:
|
||||
print(
|
||||
f"rein-aharness-claim: failed to resolve {value!r}: {exc}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
raise SystemExit(2) from exc
|
||||
if not ip or ip == "None":
|
||||
print(
|
||||
f"rein-aharness-claim: empty ClusterIP for {ns}/{svc}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
raise SystemExit(2)
|
||||
return f"http://{ip}:{port}"
|
||||
|
||||
|
||||
def _resolve_env(env: dict[str, str]) -> dict[str, str]:
|
||||
keys = (
|
||||
"LLM_CONNECT_URL",
|
||||
"ACTIVITY_CORE_URL",
|
||||
"STATE_HUB_URL",
|
||||
"STATEHUB_URL",
|
||||
)
|
||||
for key in keys:
|
||||
if key in env and env[key].startswith("k8s://"):
|
||||
env[key] = _resolve_k8s_url(env[key])
|
||||
return env
|
||||
|
||||
|
||||
def main() -> None:
|
||||
home = Path.home()
|
||||
env = os.environ.copy()
|
||||
# Default kubeconfig for k3s host users
|
||||
env.setdefault("KUBECONFIG", "/etc/rancher/k3s/k3s.yaml")
|
||||
file_env = _load_env_file(home / ".config/rein-aharness/claim-loop.env")
|
||||
env.update(file_env)
|
||||
env = _resolve_env(env)
|
||||
|
||||
rein = home / "rein-aharness" / ".venv" / "bin" / "rein-aharness"
|
||||
if not rein.is_file():
|
||||
# Fall back to PATH
|
||||
cmd = ["rein-aharness", *sys.argv[1:]]
|
||||
else:
|
||||
cmd = [str(rein), *sys.argv[1:]]
|
||||
raise SystemExit(subprocess.call(cmd, env=env))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue