amsd-pipeline 2.0.6 → 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.
- package/install.sh +86 -27
- 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
|
-
|
|
149
|
-
-f "$(basename "$_UN_COMPOSE")" -p "$_UN_PROJECT" down -v --remove-orphans --rmi local) >/dev/null 2>&1
|
|
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
|
-
|
|
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
|
|
720
|
-
EPAM_OBS_LANGFUSE_PORT
|
|
721
|
-
EPAM_OBS_DASHBOARD_PORT
|
|
722
|
-
EPAM_OBS_GRAFANA_PORT
|
|
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
|
-
|
|
725
|
-
|
|
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
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
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
|
}
|
|
@@ -894,7 +936,13 @@ else
|
|
|
894
936
|
# ./data is the container's own database — it may own that outright.
|
|
895
937
|
ensure_bind_mount_ownership "$LAUNCH_DIR/data"
|
|
896
938
|
# ./spool is the boundary the HOST runner writes; it must stay writable from both sides.
|
|
897
|
-
|
|
939
|
+
# ITS FAILURE IS THE INSTALL'S FAILURE. When this silently did nothing, the install carried on
|
|
940
|
+
# and runner-host.js died minutes later on "EACCES: mkdir .../spool/requests" — a symptom three
|
|
941
|
+
# steps from its cause. Say it where it happens.
|
|
942
|
+
if ! ensure_shared_bind_mount "$LAUNCH_DIR/spool"; then
|
|
943
|
+
_bad "spool is not writable by both the host runner and the container — the dashboard can queue no runs"
|
|
944
|
+
FAILED=1
|
|
945
|
+
fi
|
|
898
946
|
|
|
899
947
|
_LD_PORT="$(grep -E '^LAUNCH_UI_PORT=' "$LAUNCH_DIR/.env" 2>/dev/null | tail -1 | cut -d= -f2)"
|
|
900
948
|
_LD_PORT="${_LD_PORT:-8099}"
|
|
@@ -946,22 +994,33 @@ else
|
|
|
946
994
|
# 2026-09-07 under podman-compose: launch-ui kept a stale image and a stale network mode
|
|
947
995
|
# after both were changed, so the install re-tested exactly what it had just replaced and
|
|
948
996
|
# reported the old failure. A down first costs seconds and makes the up mean something.
|
|
997
|
+
# --force-recreate: `up -d --build` alone leaves an EXISTING container untouched even when
|
|
998
|
+
# the compose file that defined it has changed, so a re-install silently kept the previous
|
|
999
|
+
# install's image, network mode and published port. Live 2026-09-07: the dashboard answered
|
|
1000
|
+
# on 8099 while this install health-checked 8109, and a rebuilt UI image was never used.
|
|
1001
|
+
# A flag rather than an extra `down` — the retry below already tears down between its own
|
|
1002
|
+
# attempts, and a second teardown here changes what one attempt means.
|
|
949
1003
|
for _LD_SUBNET in $(isolated_subnet_candidates "$ROOT-launch"); do
|
|
950
1004
|
_LD_TRY_PORT=$((_LD_PORT + _LD_I * 10))
|
|
951
|
-
#
|
|
952
|
-
#
|
|
953
|
-
#
|
|
954
|
-
#
|
|
955
|
-
#
|
|
956
|
-
#
|
|
957
|
-
|
|
958
|
-
|
|
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
|
|
959
1014
|
if (cd "$LAUNCH_DIR" && LAUNCH_SUBNET="$_LD_SUBNET" LAUNCH_UI_PORT="$_LD_TRY_PORT" \
|
|
960
|
-
container_compose -f "$LAUNCH_COMPOSE" -p "$_LD_PROJECT" up -d --build) >"$_LD_LOG" 2>&1; then
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1015
|
+
container_compose -f "$LAUNCH_COMPOSE" -p "$_LD_PROJECT" up -d --build --force-recreate) >"$_LD_LOG" 2>&1; then
|
|
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
|
|
965
1024
|
fi
|
|
966
1025
|
grep -qiE 'overlap|pool|port is already allocated|address already in use' "$_LD_LOG" || break
|
|
967
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.
|
|
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"
|