diff --git a/README.md b/README.md
index c9dc8c4..62e3529 100644
--- a/README.md
+++ b/README.md
@@ -1197,6 +1197,43 @@ neu anlegt. **Proxy-Hosts, Weiterleitungen und Zugriffslisten sind damit weg**
– die Zertifikate bleiben. Das Kommando zeigt vorher genau das an und fragt
nach. Die Proxy-Hosts lassen sich mit `proxy add` in einem Aufruf neu anlegen.
+### 10.1.1 Wenn die Anmeldung fehlschlägt
+
+Die Meldung nennt inzwischen selbst, woran es liegt – sie zeigt den HTTP-Code,
+die Antwort der Schnittstelle und, falls gar nichts antwortete, was curl
+gemeldet hat:
+
+```
+[FEHLER] Anmeldung am Proxy Manager fehlgeschlagen.
+ Aufgerufen : http://127.0.0.1:81/api/tokens
+ Konto : admin@example.com
+ HTTP-Code : 400
+ Antwort : Invalid email or password
+
+ Woran es liegen kann
+ Der Proxy Manager hat geantwortet und die Anmeldung abgelehnt.
+ Der Weg dorthin stimmt also - Port, Netz und Proxy sind in Ordnung.
+```
+
+Das ist die halbe Miete: **hat es geantwortet, liegt es nicht am Netz.**
+Die andere Richtung sieht so aus:
+
+| HTTP-Code | Bedeutung | Nächster Schritt |
+|---|---|---|
+| `400`/`401` | Der Proxy Manager lehnt ab | Konto/Kennwort in der `.env`, oder das Konto gibt es nicht → `npm-reset` |
+| `000` | gar keine Antwort | Container aus? Port frei? – der Befehl prüft beides und sagt, welches zutrifft |
+| `5xx` + HTML | etwas anderes antwortet | meist der HTTP-Proxy; die erste Zeile der HTML-Antwort wird mit angezeigt |
+
+Antwortet HTML statt JSON, steht es ausdrücklich da – samt erster Zeile, an der
+man erkennt, wer da geantwortet hat:
+
+```
+ Die Antwort ist HTML, kein JSON - sie stammt also nicht von der
+ Schnittstelle des Proxy Managers, sondern von etwas davor
+ (HTTP-Proxy, anderer Dienst auf dem Port). Erste Zeile:
+
502 Proxy Error...
+```
+
### 10.2 Proxy-Host anlegen – ohne Browser
Die Weboberfläche lässt sich im Terminal-Browser nur mühsam bedienen; Formulare
diff --git a/README_en.md b/README_en.md
index a54ee3d..e6271d4 100644
--- a/README_en.md
+++ b/README_en.md
@@ -1196,6 +1196,42 @@ the account from `NPM_ADMIN_EMAIL`/`NPM_ADMIN_PASSWORD` on the next `up`.
remain. The command shows exactly that beforehand and asks for confirmation.
The proxy hosts can be recreated with `proxy add` in a single call.
+### 10.1.1 When the login fails
+
+The message now names the cause itself – it shows the HTTP code, the API's
+reply and, if nothing answered at all, what curl reported:
+
+```
+[FEHLER] Anmeldung am Proxy Manager fehlgeschlagen.
+ Aufgerufen : http://127.0.0.1:81/api/tokens
+ Konto : admin@example.com
+ HTTP-Code : 400
+ Antwort : Invalid email or password
+
+ Woran es liegen kann
+ Der Proxy Manager hat geantwortet und die Anmeldung abgelehnt.
+ Der Weg dorthin stimmt also - Port, Netz und Proxy sind in Ordnung.
+```
+
+That is half the battle: **if it answered, the network is not the problem.**
+The other direction looks like this:
+
+| HTTP code | meaning | next step |
+|---|---|---|
+| `400`/`401` | the Proxy Manager refuses | account/password in `.env`, or the account does not exist → `npm-reset` |
+| `000` | no answer at all | container down? port free? – the command checks both and says which applies |
+| `5xx` + HTML | something else answered | usually the HTTP proxy; the first line of the HTML reply is shown |
+
+If HTML arrives instead of JSON, it says so explicitly – including the first
+line, which reveals who answered:
+
+```
+ Die Antwort ist HTML, kein JSON - sie stammt also nicht von der
+ Schnittstelle des Proxy Managers, sondern von etwas davor
+ (HTTP-Proxy, anderer Dienst auf dem Port). Erste Zeile:
+ 502 Proxy Error...
+```
+
### 10.2 Creating a proxy host – without a browser
The web interface is painful in a terminal browser, and forms with file uploads
diff --git a/scripts/cmk-manage.sh b/scripts/cmk-manage.sh
index cf99fb5..717dd4d 100755
--- a/scripts/cmk-manage.sh
+++ b/scripts/cmk-manage.sh
@@ -3769,31 +3769,135 @@ EOF
fi
return 1
fi
- local body
- body="$(curl -sS --max-time 20 --noproxy '*' -X POST "$base/api/tokens" \
+ # Antwort, HTTP-Code und curls eigene Fehlermeldung getrennt
+ # einsammeln - ohne die drei laesst sich hinterher nicht sagen, WORAN
+ # es lag, und genau das ist hier der haeufigste Zeitfresser.
+ local body code cerr rc=0
+ cerr="$(mktemp)"
+ body="$(curl -sS --max-time 20 --noproxy '*' -w '\n%{http_code}' \
+ -X POST "$base/api/tokens" \
-H 'Content-Type: application/json' \
- -d "{\"identity\":\"$NPM_ADMIN_EMAIL\",\"secret\":\"$NPM_ADMIN_PASSWORD\"}" 2>/dev/null)" || true
+ -d "{\"identity\":\"$NPM_ADMIN_EMAIL\",\"secret\":\"$NPM_ADMIN_PASSWORD\"}" \
+ 2>"$cerr")" || rc=$?
+ code="${body##*$'\n'}"; body="${body%$'\n'*}"
+ case "$code" in ''|*[!0-9]*) code=000 ;; esac
+
local tok; tok="$(json_str "$body" token)"
- if [ -z "$tok" ]; then
- err "Anmeldung am Proxy Manager fehlgeschlagen."
- local m; m="$(json_str "$body" message)"
- if [ -n "$m" ]; then printf ' Antwort: %s\n' "$m" >&2; fi
- printf ' Geprueft wurde: %s\n' "$base/api/tokens" >&2
- # In Kundennetzen mit Zwangsproxy ist das die haeufigste Ursache
- # fuer eine Fehlermeldung, die nach einem API-Problem aussieht.
- if [ -n "${http_proxy:-}${HTTP_PROXY:-}${https_proxy:-}${HTTPS_PROXY:-}" ]; then
- printf '
- In dieser Umgebung steht ein HTTP-Proxy. Nimmt no_proxy die lokalen
- Adressen nicht aus, geht selbst diese Anfrage an ihn - dann meldet
- er den Fehler, nicht der Proxy Manager. Nachsehen mit:
- %s noproxy
-' "$SELF" >&2
- fi
- return 1
+ if [ -n "$tok" ]; then
+ rm -f "$cerr"
+ printf '%s' "$tok"
+ return 0
fi
- printf '%s' "$tok"
+
+ err "Anmeldung am Proxy Manager fehlgeschlagen."
+ printf ' Aufgerufen : %s\n' "$base/api/tokens" >&2
+ printf ' Konto : %s\n' "${NPM_ADMIN_EMAIL:-}" >&2
+ printf ' HTTP-Code : %s\n' "$code" >&2
+ local cmsg; cmsg="$(sed -n '1p' "$cerr" 2>/dev/null)"
+ if [ -n "$cmsg" ]; then printf ' curl sagt : %s\n' "$cmsg" >&2; fi
+ rm -f "$cerr"
+ # Der Proxy Manager verpackt seine Meldung in "error" - sie ist die
+ # nuetzlichste Zeile ueberhaupt und gehoert nach oben, nicht ans Ende.
+ local m; m="$(json_str "$body" message)"
+ if [ -n "$m" ]; then printf ' Antwort : %s\n' "$m" >&2; fi
+
+ printf '\n %sWoran es liegen kann%s\n' "$C_BLD" "$C_RST" >&2
+
+ case "$code" in
+ 400|401|403)
+ # Es hat geantwortet - der Weg stimmt also, nur die Daten nicht.
+ printf ' Der Proxy Manager hat geantwortet und die Anmeldung abgelehnt.
+ Der Weg dorthin stimmt also - Port, Netz und Proxy sind in Ordnung.\n' >&2
+ case "$m" in
+ *"fewer than"*|*"must NOT"*|*"required"*)
+ printf '
+ Die Anfrage war unvollstaendig - meist ein leerer Wert in der .env:
+ NPM_ADMIN_EMAIL = %s
+ NPM_ADMIN_PASSWORD = %s
+ Setzen mit: %s config set NPM_ADMIN_PASSWORD \n' \
+ "${NPM_ADMIN_EMAIL:-}" \
+ "$([ -n "${NPM_ADMIN_PASSWORD:-}" ] && echo '' || echo '')" \
+ "$SELF" >&2 ;;
+ *)
+ printf '
+ Konto oder Kennwort stimmt nicht. Beide stehen in der .env:
+ %s config set NPM_ADMIN_EMAIL
+ %s config set NPM_ADMIN_PASSWORD
+
+ Gibt es das Konto ueberhaupt? Seit Version 2.15 legt der Proxy
+ Manager keine Standardzugangsdaten an; das Konto entsteht nur beim
+ ERSTEN Start mit leerer Datenbank aus NPM_ADMIN_EMAIL/-PASSWORD.
+ War die Datenbank damals schon da, wurde es nie angelegt:
+ %s npm-reset (Datenbank beiseite, Konto entsteht neu)
+ Oder von Hand in der Oberflaeche: %s browser\n' \
+ "$SELF" "$SELF" "$SELF" "$SELF" >&2 ;;
+ esac
+ ;;
+ 000)
+ printf ' Es kam ueberhaupt keine HTTP-Antwort.\n' >&2
+ # Der Reihe nach das Naheliegende pruefen und BENENNEN
+ if ! npm_enabled; then
+ printf ' -> NPM_ENABLED=off - der Proxy Manager soll gar nicht laufen.
+ Einschalten: %s npm-enable on\n' "$SELF" >&2
+ elif ! container_running "$NPM_CONTAINER_NAME"; then
+ printf ' -> Der Container "%s" laeuft nicht.
+ Starten: %s up\n' "$NPM_CONTAINER_NAME" "$SELF" >&2
+ elif ! port_in_use "${NPM_ADMIN_PORT:-81}"; then
+ printf ' -> Auf Port %s lauscht nichts.
+ Der Container laeuft, aber die Oberflaeche ist dort nicht zu
+ erreichen. Nachsehen: %s logs
+ Port pruefen/aendern: %s npm-port\n' \
+ "${NPM_ADMIN_PORT:-81}" "$SELF" "$SELF" >&2
+ else
+ printf ' -> Port %s ist belegt, antwortet aber nicht auf diese Anfrage.
+ Vielleicht startet der Dienst noch: %s proxy restart\n' \
+ "${NPM_ADMIN_PORT:-81}" "$SELF" >&2
+ fi
+ case "$cmsg" in
+ *proxy*|*Proxy*)
+ printf ' -> curl nennt einen Proxy. Pruefen: %s noproxy\n' "$SELF" >&2 ;;
+ esac
+ ;;
+ 5??)
+ printf ' Es hat etwas geantwortet, aber mit einem Serverfehler.
+ Kommt die Antwort ueberhaupt vom Proxy Manager? Ein
+ HTTP-Proxy im Netz antwortet an dieser Stelle gern selbst:
+ %s noproxy\n' "$SELF" >&2
+ ;;
+ *)
+ printf ' Unerwartete Antwort - erwartet wurde ein Feld "token".\n' >&2
+ ;;
+ esac
+
+ # Sieht die Antwort nach einer Webseite aus, kommt sie nicht von der
+ # Schnittstelle - das ist das sicherste Zeichen fuer einen Proxy
+ # oder einen fremden Dienst auf dem Port.
+ case "$body" in
+ '<'*|*'&2 ;;
+ '')
+ : ;;
+ *)
+ if [ -z "$m" ]; then
+ printf '\n Antwort (gekuerzt): %s\n' "$(printf '%s' "$body" | tr -d '\n' | cut -c1-120)" >&2
+ fi ;;
+ esac
+
+ if [ -n "${http_proxy:-}${https_proxy:-}${HTTPS_PROXY:-}" ]; then
+ printf '
+ In dieser Umgebung steht ein HTTP-Proxy. Die eigenen Aufrufe gehen
+ zwar mit "--noproxy" daran vorbei, eigene Tests aber nicht:
+ %s noproxy\n' "$SELF" >&2
+ fi
+ printf '\n' >&2
+ return 1
}
+
+
# npm_api METHODE PFAD [JSON] -> Antwort auf stdout, HTTP-Code via npm_code
NPM_CODE_FILE="${TMPDIR:-/tmp}/.cmk-manage-npmcode.$$"
trap 'rm -f "$NPM_CODE_FILE"' EXIT
diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh
index a859d81..b7e478b 100644
--- a/scripts/lib/common.sh
+++ b/scripts/lib/common.sh
@@ -148,8 +148,13 @@ npm_enabled() {
esac
}
-container_exists() { $RUNTIME container inspect "$1" >/dev/null 2>&1; }
-container_running() { [ "$($RUNTIME container inspect -f '{{.State.Running}}' "$1" 2>/dev/null)" = "true" ]; }
+# Ohne erkannte Runtime laesst sich nichts sagen - dann schlicht "nein"
+# statt unter "set -u" mitten in einer Fehlerdiagnose abzubrechen.
+container_exists() { [ -n "${RUNTIME:-}" ] && $RUNTIME container inspect "$1" >/dev/null 2>&1; }
+container_running() {
+ [ -n "${RUNTIME:-}" ] || return 1
+ [ "$($RUNTIME container inspect -f '{{.State.Running}}' "$1" 2>/dev/null)" = "true" ]
+}
require_cmk_running() {
container_exists "$CMK_CONTAINER_NAME" \