amsd-pipeline 2.0.7 → 2.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/install.sh +72 -17
  2. package/package.json +1 -1
package/install.sh CHANGED
@@ -145,11 +145,20 @@ if [ "$UNINSTALL" = "1" ]; then
145
145
  _UN_FILE="${_UN_SPEC%%:*}"; _UN_PROJECT="${_UN_SPEC##*:}"
146
146
  _UN_COMPOSE="$_UN_ROOT/$_UN_FILE"
147
147
  if [ -f "$_UN_COMPOSE" ]; then
148
- if (cd "$(dirname "$_UN_COMPOSE")" && container_compose \
149
- -f "$(basename "$_UN_COMPOSE")" -p "$_UN_PROJECT" down -v --remove-orphans --rmi local) >/dev/null 2>&1; then
148
+ (cd "$(dirname "$_UN_COMPOSE")" && container_compose \
149
+ -f "$(basename "$_UN_COMPOSE")" -p "$_UN_PROJECT" down -v --remove-orphans --rmi local) >/dev/null 2>&1 || true
150
+ # COMPOSE DOWN IS NOT THE WHOLE JOB, AND ITS EXIT CODE IS NOT THE ANSWER. A non-zero
151
+ # `down` used to be reported as "nothing to remove or already gone" — the most
152
+ # reassuring wording available for the case where nothing was removed. Live
153
+ # 2026-09-07 that left EIGHT containers and TWO networks behind, which then held the
154
+ # ports the next install needed, so a fresh install validated itself against the
155
+ # previous install's services. Sweep by label, then verify, then report the machine's
156
+ # actual state rather than a command's exit code.
157
+ if purge_project "$_UN_PROJECT"; then
150
158
  _ok "removed $_UN_PROJECT (containers, network, volumes, images)"
151
159
  else
152
- _ok "$_UN_PROJECT: nothing to remove or already gone"
160
+ _bad "$_UN_PROJECT: containers remain after uninstall they will hold this install's ports"
161
+ FAILED=1
153
162
  fi
154
163
  # SCOPED PRUNE, never a bare `docker system prune` — that would also sweep up the dev
155
164
  # environment's own dangling layers. Compose stamps every image it builds with this
@@ -715,14 +724,32 @@ compose_up() {
715
724
  # exact stack already running, or a second install) steps to the next attempt's offset, so
716
725
  # no manual port flag is ever required for this to just work.
717
726
  local _off=$((_i * 10))
727
+ # PROBED, NOT ASSUMED. The offset says where to START looking; whether a port is free is
728
+ # a question only the machine can answer. Deriving them arithmetically meant a clash was
729
+ # discovered only when compose failed — and compose does not always fail: live 2026-09-07
730
+ # it exited 0 over six containers stuck in `created` with "address already in use", so
731
+ # nothing discovered the clash at all. Each service takes the first genuinely free port
732
+ # at or after its candidate, so another install holding 3100 costs one step, not a run.
733
+ local _p_ch _p_lf _p_dash _p_graf
734
+ _p_ch="$(find_free_port $((8123 + _off)))" || { _bad "no free port for clickhouse"; return 1; }
735
+ _p_lf="$(find_free_port $((3100 + _off)))" || { _bad "no free port for langfuse"; return 1; }
736
+ _p_dash="$(find_free_port $((8092 + _off)))" || { _bad "no free port for the dashboard"; return 1; }
737
+ _p_graf="$(find_free_port $((3001 + _off)))" || { _bad "no free port for grafana"; return 1; }
718
738
  if (cd "$ROOT" && EPAM_OBS_SUBNET="$_subnet" \
719
- EPAM_OBS_CLICKHOUSE_PORT=$((8123 + _off)) \
720
- EPAM_OBS_LANGFUSE_PORT=$((3100 + _off)) \
721
- EPAM_OBS_DASHBOARD_PORT=$((8092 + _off)) \
722
- EPAM_OBS_GRAFANA_PORT=$((3001 + _off)) \
739
+ EPAM_OBS_CLICKHOUSE_PORT="$_p_ch" \
740
+ EPAM_OBS_LANGFUSE_PORT="$_p_lf" \
741
+ EPAM_OBS_DASHBOARD_PORT="$_p_dash" \
742
+ EPAM_OBS_GRAFANA_PORT="$_p_graf" \
723
743
  container_compose -f "$COMPOSE_FILE" -p "$_OBS_PROJECT" up -d) >"$_log" 2>&1; then
724
- _up=0
725
- break
744
+ # UP EXITED 0 — THAT IS NOT THE SAME AS RUNNING. podman-compose returns 0 with
745
+ # containers left in `created`; live 2026-09-07 six of eight sat there holding
746
+ # "address already in use" while this loop recorded success and never retried the
747
+ # next port offset. Appending to the SAME log the retry greps means the container's
748
+ # own error can match 'address already in use' and drive the next attempt.
749
+ if compose_services_running "$_OBS_PROJECT" >>"$_log" 2>&1; then
750
+ _up=0
751
+ break
752
+ fi
726
753
  fi
727
754
  # ONLY RETRY ON A SUBNET OR PORT COLLISION — any other failure would fail identically on
728
755
  # every candidate, burning through all of them and hiding the real error behind repeats.
@@ -750,10 +777,15 @@ compose_up() {
750
777
  {
751
778
  printf 'OBS_PROJECT=%s\n' "$_OBS_PROJECT"
752
779
  printf 'OBS_SUBNET=%s\n' "$_subnet"
753
- printf 'OBS_CLICKHOUSE_PORT=%s\n' "$((8123 + _off))"
754
- printf 'OBS_LANGFUSE_PORT=%s\n' "$((3100 + _off))"
755
- printf 'OBS_DASHBOARD_PORT=%s\n' "$((8092 + _off))"
756
- printf 'OBS_GRAFANA_PORT=%s\n' "$((3001 + _off))"
780
+ # THE PORTS ACTUALLY USED, not the ones arithmetic proposed. These are probed now
781
+ # (find_free_port), so an offset that was occupied yields a different port — recording
782
+ # the formula instead of the result would make this file name ports no container listens
783
+ # on, and service_url()/langfuse-emit.js read it to find this install's own services.
784
+ printf 'OBS_CLICKHOUSE_PORT=%s\n' "$_p_ch"
785
+ printf 'OBS_LANGFUSE_PORT=%s\n' "$_p_lf"
786
+ printf 'OBS_DASHBOARD_PORT=%s\n' "$_p_dash"
787
+ printf 'OBS_GRAFANA_PORT=%s\n' "$_p_graf"
788
+ # (the rest of the identity — mock server, etc — follows below)
757
789
  # THE REHEARSAL SERVER'S IDENTITY, resolved here and started nowhere.
758
790
  #
759
791
  # llm-defaults.mockserver.json points all 40 seams at MockServer, and until now nothing in
@@ -771,6 +803,16 @@ compose_up() {
771
803
  printf 'MOCK_PROJECT=%s\n' "$(isolated_project_name "$ROOT" mock)"
772
804
  printf 'MOCK_SUBNET=%s\n' "$(isolated_subnet_candidates "$ROOT-mock" | head -1)"
773
805
  } > "$ROOT/.pipeline-services-state.env"
806
+
807
+ # THE .env MUST NAME THIS INSTALL'S OWN SERVICES. langfuse-emit.js resolves
808
+ # `env.LANGFUSE_BASE_URL || allocatedBase()`, so a literal in .env WINS over what this install
809
+ # allocated. Live 2026-09-07: an install whose Langfuse came up on 3120 carried a copied
810
+ # LANGFUSE_BASE_URL=http://localhost:3100 — a PREVIOUS install's — so every trace from a run
811
+ # would have been written into that other install's database, while looking perfectly healthy.
812
+ # Copied .env files are the normal case here, not an edge one.
813
+ if reconcile_env_endpoint "$ROOT/.env" LANGFUSE_BASE_URL "http://localhost:${_p_lf}"; then
814
+ _ok "LANGFUSE_BASE_URL points at this install's own Langfuse (port ${_p_lf})"
815
+ fi
774
816
  rm -f "$_log" 2>/dev/null
775
817
  return 0
776
818
  }
@@ -960,12 +1002,25 @@ else
960
1002
  # attempts, and a second teardown here changes what one attempt means.
961
1003
  for _LD_SUBNET in $(isolated_subnet_candidates "$ROOT-launch"); do
962
1004
  _LD_TRY_PORT=$((_LD_PORT + _LD_I * 10))
1005
+ # WRITTEN INTO THE .env COMPOSE READS, not only exported. Docker Compose lets the
1006
+ # shell environment win over the project .env; PODMAN-COMPOSE DOES NOT — with
1007
+ # LAUNCH_UI_PORT=8109 exported, `podman compose config` still resolved `ports:
1008
+ # 8099:80` from launch-dashboard/.env. So every retry republished the SAME port while
1009
+ # the installer health-checked the next one, and a dashboard that was up and serving
1010
+ # on 8099 was declared "never answered healthy at :8109". Writing the file is correct
1011
+ # on both runtimes — docker reads it too — and removes the precedence difference
1012
+ # rather than depending on it.
1013
+ reconcile_env_endpoint "$LAUNCH_DIR/.env" LAUNCH_UI_PORT "$_LD_TRY_PORT" || true
963
1014
  if (cd "$LAUNCH_DIR" && LAUNCH_SUBNET="$_LD_SUBNET" LAUNCH_UI_PORT="$_LD_TRY_PORT" \
964
1015
  container_compose -f "$LAUNCH_COMPOSE" -p "$_LD_PROJECT" up -d --build --force-recreate) >"$_LD_LOG" 2>&1; then
965
- _LD_UP=0
966
- _LD_PORT="$_LD_TRY_PORT"
967
- _LD_HEALTH_URL="http://localhost:${_LD_PORT}/api/health"
968
- break
1016
+ # Same trap as the observability stack: compose can exit 0 over containers that
1017
+ # never started, and the port-collision retry below only fires on a failure.
1018
+ if compose_services_running "$_LD_PROJECT" >>"$_LD_LOG" 2>&1; then
1019
+ _LD_UP=0
1020
+ _LD_PORT="$_LD_TRY_PORT"
1021
+ _LD_HEALTH_URL="http://localhost:${_LD_PORT}/api/health"
1022
+ break
1023
+ fi
969
1024
  fi
970
1025
  grep -qiE 'overlap|pool|port is already allocated|address already in use' "$_LD_LOG" || break
971
1026
  # TEAR DOWN BEFORE THE NEXT ATTEMPT — same fix as the observability stack's retry
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amsd-pipeline",
3
- "version": "2.0.7",
3
+ "version": "2.0.8",
4
4
  "description": "Installer for the amsd-pipeline orchestration stack. Clones, packages and provisions the full stack with one command — no separate git clone step.",
5
5
  "bin": {
6
6
  "amsd-pipeline": "bin/amsd-pipeline.js"