Commit 19fde60c authored by Yann Garcia's avatar Yann Garcia
Browse files

Terminate orchestration

parent 209ae57a
Loading
Loading
Loading
Loading
+65 −6
Changes for tools/simu5g/install-simu5g-routes-sandbox.sh: 65 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -170,9 +170,55 @@ parse_args() {
  fi
}

# When the integration config lists ueMappings / mecEndpoints, classify by those
# id prefixes (ue1 → ue1-iperf-…, zone1-edge1 → zone1-edge1-iperf-…). Otherwise
# keep the monaco-harbor default: MEC name starts with MEC_NAME_PREFIX (mep).
MEC_PREFIXES=()
UE_PREFIXES=()

load_config_name_prefixes() {
  MEC_PREFIXES=()
  UE_PREFIXES=()
  [[ -f "$CONFIG_FILE" ]] || return 0
  command -v python3 >/dev/null 2>&1 || return 0
  local mec_line ue_line
  mec_line="$(python3 -c 'import json,sys; c=json.load(open(sys.argv[1],encoding="utf-8")); print(" ".join(str(m.get("endpointId") or "").strip() for m in (c.get("mecEndpoints") or []) if str(m.get("endpointId") or "").strip()))' "$CONFIG_FILE")" || return 0
  ue_line="$(python3 -c 'import json,sys; c=json.load(open(sys.argv[1],encoding="utf-8")); print(" ".join(str(u.get("ueId") or "").strip() for u in (c.get("ueMappings") or []) if str(u.get("ueId") or "").strip()))' "$CONFIG_FILE")" || return 0
  read -r -a MEC_PREFIXES <<< "$mec_line"
  read -r -a UE_PREFIXES <<< "$ue_line"
}

name_matches_prefixes() {
  local name=$1
  shift
  local p
  for p in "$@"; do
    [[ -n "$p" ]] || continue
    if [[ "$name" == "$p" || "$name" == "${p}-iperf"* || "$name" == "${p}-"* ]]; then
      # Prefer traffic pods; skip *-svc (demo-server) when a tighter prefix exists.
      [[ "$name" == *"-svc"* ]] && continue
      return 0
    fi
  done
  return 1
}

is_mec_pod_name() {
  local name=$1
  if ((${#MEC_PREFIXES[@]})); then
    name_matches_prefixes "$name" "${MEC_PREFIXES[@]}"
  else
    [[ "$name" == "${MEC_NAME_PREFIX}"* ]]
  fi
}

is_ue_pod_name() {
  local name=$1
  if ((${#UE_PREFIXES[@]})); then
    name_matches_prefixes "$name" "${UE_PREFIXES[@]}"
  else
    ! is_mec_pod_name "$name"
  fi
}

pods_to_cidr_csv() {
@@ -219,6 +265,7 @@ list_scenario_pods() {

discover_pod_groups() {
  command -v "$KUBECTL" >/dev/null 2>&1 || die "kubectl not found"
  load_config_name_prefixes

  local mec_names=() ue_names=()
  local mec_ips=() ue_ips=()
@@ -228,15 +275,20 @@ discover_pod_groups() {
    if is_mec_pod_name "$name"; then
      mec_names+=("$name")
      mec_ips+=("$ip")
    else
    elif is_ue_pod_name "$name"; then
      ue_names+=("$name")
      ue_ips+=("$ip")
    fi
  done < <(list_scenario_pods)

  # Logical selectors (document how pods were chosen; not valid as a single kubectl -l name filter).
  if ((${#MEC_PREFIXES[@]})); then
    MEC_POD_SELECTOR="${SCENARIO_SELECTOR} + name prefix ${MEC_PREFIXES[*]}"
    UE_POD_SELECTOR="${SCENARIO_SELECTOR} + name prefix ${UE_PREFIXES[*]}"
  else
    MEC_POD_SELECTOR="${SCENARIO_SELECTOR} + pod name ^${MEC_NAME_PREFIX}"
    UE_POD_SELECTOR="${SCENARIO_SELECTOR} + pod name !^${MEC_NAME_PREFIX}"
  fi

  MEC_CIDRS=$(printf '%s\n' "${mec_ips[@]:-}" | pods_to_cidr_csv)
  UE_CIDRS=$(printf '%s\n' "${ue_ips[@]:-}" | pods_to_cidr_csv)
@@ -272,8 +324,10 @@ discover_pod_groups() {
    done
  fi

  [[ -n "$MEC_CIDRS" ]] || die "no MEC pods (name prefix '${MEC_NAME_PREFIX}') in namespace ${SANDBOX_NS}"
  [[ -n "$UE_CIDRS" ]] || die "no UE pods (non-${MEC_NAME_PREFIX} scenario pods) in namespace ${SANDBOX_NS}"
  local mec_want="${MEC_PREFIXES[*]:-$MEC_NAME_PREFIX}"
  local ue_want="${UE_PREFIXES[*]:-non-${MEC_NAME_PREFIX}}"
  [[ -n "$MEC_CIDRS" ]] || die "no MEC pods (prefix '${mec_want}') in namespace ${SANDBOX_NS}"
  [[ -n "$UE_CIDRS" ]] || die "no UE pods (prefix '${ue_want}') in namespace ${SANDBOX_NS}"
  rewrite_config_from_pods
}

@@ -306,10 +360,15 @@ with open(cfg_path, encoding="utf-8") as f:
    cfg = json.load(f)

def match(prefix):
    exact = iperf = other = None
    for name, ip in pods:
        if name == prefix or name.startswith(prefix + "-"):
            return ip
    return None
        if name == prefix:
            exact = ip
        elif name.startswith(prefix + "-iperf"):
            iperf = ip
        elif name.startswith(prefix + "-") and "-svc" not in name:
            other = other or ip
    return iperf or exact or other

n = 0
for ue in cfg.get("ueMappings") or []:
+110 −12
Changes for tools/simu5g/simu5g_activate.py: 110 added lines, 12 removed lines.
Original line number Diff line number Diff line
@@ -179,14 +179,31 @@ def start_daemon(name, argv, log_path):
    return proc.pid


def wait_for_pods(namespace, timeout=120):
def _name_prefixes(cfg, key, id_field):
    out = []
    for row in (cfg or {}).get(key) or []:
        ident = str(row.get(id_field) or "").strip()
        if ident:
            out.append(ident)
    return out


def _pod_matches(name, prefixes, fallback):
    if prefixes:
        return any(name == p or name.startswith(p + "-") for p in prefixes)
    return fallback(name)


def wait_for_pods(namespace, timeout=120, cfg=None):
    ue_prefixes = _name_prefixes(cfg, "ueMappings", "ueId")
    mec_prefixes = _name_prefixes(cfg, "mecEndpoints", "endpointId")
    deadline = time.time() + timeout
    while time.time() < deadline:
        r = kubectl("get", "pods", "-n", namespace, "--field-selector=status.phase=Running",
                    "-o", "jsonpath={.items[*].metadata.name}")
        names = (r.stdout or "").split()
        ues = [n for n in names if n.startswith("ue-")]
        mec = [n for n in names if n.startswith("mep")]
        ues = [n for n in names if _pod_matches(n, ue_prefixes, lambda x: x.startswith("ue"))]
        mec = [n for n in names if _pod_matches(n, mec_prefixes, lambda x: x.startswith("mep"))]
        if ues and mec:
            _log(f"pods ready: {len(ues)} UE, {len(mec)} MEC")
            return True
@@ -195,6 +212,79 @@ def wait_for_pods(namespace, timeout=120):
    return False


def _live_pod_ip(namespace, prefix):
    r = kubectl(
        "get", "pods", "-n", namespace, "-o",
        r"jsonpath={range .items[*]}{.metadata.name}{'\t'}{.status.podIP}{'\n'}{end}",
    )
    for line in (r.stdout or "").splitlines():
        name, _, ip = line.partition("\t")
        name, ip = name.strip(), ip.strip()
        if ip and (name == prefix or name.startswith(prefix + "-")):
            return ip
    return ""


def inject_edge_pod_ip(namespace, cfg):
    """Pin UE iperf clients to the MEC PodIP so ClusterIP cannot skip TUN."""
    mecs = (cfg or {}).get("mecEndpoints") or []
    ues = (cfg or {}).get("ueMappings") or []
    if not mecs or not ues:
        return False
    eid = str(mecs[0].get("endpointId") or "").strip()
    edge_ip = _live_pod_ip(namespace, eid) if eid else ""
    if not edge_ip:
        _log(f"WARN: no PodIP for MEC prefix {eid or '?'}")
        return False
    patched = False
    for ue in ues:
        uid = str(ue.get("ueId") or "").strip()
        if not uid:
            continue
        for deploy in (f"{uid}-iperf", uid):
            chk = kubectl("get", "deploy", deploy, "-n", namespace)
            if chk.returncode != 0:
                continue
            setr = kubectl(
                "set", "env", f"deploy/{deploy}",
                f"EDGE_IPERF_POD_IP={edge_ip}", "-n", namespace,
            )
            if setr.returncode == 0:
                _log(f"set {deploy} EDGE_IPERF_POD_IP={edge_ip}")
                patched = True
            else:
                _log(f"WARN: kubectl set env {deploy}: {setr.stderr or setr.stdout}")
            break
    return patched


def config_template_for_instance(args, inst):
    """Prefer the example-tree config, then tools/simu5g/<id>-integration-config.json.

    Self-contained examples ship tools/simu5g mappings next to the YAML:
      examples/<scenario_id>/integration-config.json
      examples/<scenario_id>/<scenario_id>-integration-config.json
    monaco-harbor and other host-only templates stay under tools/simu5g/.
    An explicit --config-file (not the monaco-harbor default) still wins.
    """
    given = Path(args.config_file)
    sid = str((inst or {}).get("scenario_id") or "").strip()
    explicit = given.resolve() != DEFAULT_CONFIG.resolve()
    if explicit and given.is_file():
        return given
    candidates = []
    if sid:
        ex = REPO_ROOT / "examples" / sid
        candidates.append(ex / "integration-config.json")
        candidates.append(ex / f"{sid}-integration-config.json")
        candidates.append(SCRIPT_DIR / f"{sid}-integration-config.json")
    for path in candidates:
        if path.is_file():
            _log(f"using scenario template {path}")
            return path
    return given


def gis_base_url(namespace):
    r = kubectl("get", "svc", "meep-gis-engine", "-n", namespace,
                "-o", "jsonpath={.spec.clusterIP}")
@@ -278,15 +368,12 @@ def activate_as_root(cfg_path, sandbox_id, slot, namespace):
    tun = (cfg.get("bridge") or {}).get("tunName") or tun_name(slot, sandbox_id)
    port = int((cfg.get("bridge") or {}).get("connectPort") or (5555 + int(slot) * 10))

    start_daemon(
        "bridge",
        [str(bridge_bin), "--config", str(cfg_path), "--sandbox", sandbox_id,
         "--slot", str(slot), "--tun", tun, "--connect-port", str(port)],
        daemon_log_path("bridge", sandbox_id),
    )

    pods_ok = wait_for_pods(namespace)
    # Rewrite live /32s and install policy routes before HELLO so Simu5G NAT
    # is not sent empty sandboxIpCidr (demo1 has no mep* pods).
    pods_ok = wait_for_pods(namespace, cfg=cfg)
    if pods_ok:
        inject_edge_pod_ip(namespace, cfg)
        wait_for_pods(namespace, cfg=cfg, timeout=60)
        runner.invoke_routes(
            "apply",
            namespace=namespace,
@@ -295,6 +382,16 @@ def activate_as_root(cfg_path, sandbox_id, slot, namespace):
            sandbox_id=sandbox_id,
            slot=slot,
        )
        cfg = json.loads(Path(cfg_path).read_text(encoding="utf-8"))
        tun = (cfg.get("bridge") or {}).get("tunName") or tun
        port = int((cfg.get("bridge") or {}).get("connectPort") or port)

    start_daemon(
        "bridge",
        [str(bridge_bin), "--config", str(cfg_path), "--sandbox", sandbox_id,
         "--slot", str(slot), "--tun", tun, "--connect-port", str(port)],
        daemon_log_path("bridge", sandbox_id),
    )

    gis_url = ""
    for _ in range(30):
@@ -429,7 +526,8 @@ def run_via_kubectl_job(sandbox_id, action, config_file=None):


def prepare_config(args, inst=None):
    cfg_file = Path(args.config_file)
    cfg_file = config_template_for_instance(args, inst)
    args.config_file = str(cfg_file)
    cfg = json.loads(cfg_file.read_text(encoding="utf-8"))
    sandbox = args.namespace
    if inst is None: