"manifest unknown" erklaeren - und eine Pipe-Falle beseitigen, die das
Erkennen verhindert hat
Der Pull meldete "manifest unknown". Das heisst, anders als zuvor: der
Repository-Pfad registry.checkmk.com/enterprise/check-mk-enterprise ist
richtig und die Anmeldung auch - nur das Tag 2.4.0p9 gibt es dort nicht.
Neu "image why [REF]" unterscheidet die drei Faelle anhand der Registry
statt anhand der Fehlermeldung:
401/403 Anmeldung oder Berechtigung
404 Repository gibt es nicht -> image repos
Tag Repository ja, Tag nein -> vorhandene Tags des
Zweigs werden aufgelistet
"up" ruft das von selbst auf, wenn das Starten scheitert und das Image
nicht lokal vorliegt; "image pull" ebenfalls.
Beim Bauen stellte sich heraus, dass die Tag-Pruefung immer "nicht
vorhanden" meldete - auch fuer Tags, die es gibt. Ursache ist eine
Falle, die das ganze Projekt betraf:
printf ... | grep -q muster
"grep -q" endet beim ersten Treffer. Der Erzeuger bekommt dann SIGPIPE,
und unter "set -o pipefail" gilt die ganze Pipe als fehlgeschlagen -
aber nur, wenn er noch am Schreiben war. Bei drei Zeilen faellt das nie
auf, bei 2393 Tags immer. Nachgestellt:
set -euo pipefail; seq 1 500000 | grep -qx 3 -> schlaegt fehl
Betroffen waren zwoelf Stellen, darunter zwei, die ernster sind als die
Tag-Liste: bundle_read prueft mit "tar -tzf ... | grep -qx", ob ein
Backup ein Bundle ist. Bei einem grossen Archiv haette ein gueltiges
Bundle als "kein Bundle" gegolten - also ein stiller Fehler bei Restore
und Import genau dann, wenn das Backup gross ist. Alle zwoelf laufen
jetzt in einer Subshell ohne pipefail.
Der Selbsttest hat dafuer eine eigene Pruefung bekommen, damit die
Schreibweise nicht zurueckkehrt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+137
-18
@@ -119,6 +119,8 @@ KOMMANDOS - Checkmk-Image beschaffen
|
||||
--limit N hoechstens N Eintraege (Vorgabe 25), --all fuer alle
|
||||
--user U --password P statt der Werte aus der .env
|
||||
--bare nur die nackte Liste, ohne Rahmen
|
||||
image why [REF] erklaeren, warum sich eine Referenz nicht holen
|
||||
laesst (ohne REF: die aus CMK_IMAGE)
|
||||
image repos [Opt.] herausfinden, welche Repositories die Registry
|
||||
wirklich anbietet (Katalog + uebliche Pfade)
|
||||
image test [Opt.] Zugangsdaten pruefen, ohne etwas herunterzuladen
|
||||
@@ -244,7 +246,13 @@ bundle_read() {
|
||||
B_BUNDLE_TYPE=""; B_ARCHIVE_SIZE=""; B_OMD_BACKUP_OPTS=""; B_SOURCE_OS=""
|
||||
B_IS_BUNDLE=0
|
||||
|
||||
if tar -tzf "$file" 2>/dev/null | grep -qx "$BUNDLE_DIRNAME/MANIFEST"; then
|
||||
# ACHTUNG: "grep -q" beendet sich beim ersten Treffer. Der Erzeuger
|
||||
# bekommt dann SIGPIPE, und unter "set -o pipefail" gilt die ganze
|
||||
# Pipe als fehlgeschlagen - aber nur, wenn er noch am Schreiben war,
|
||||
# also abhaengig von der Datenmenge. Bei einem grossen Archiv wuerde
|
||||
# ein vorhandenes Bundle dadurch als "kein Bundle" gelten. Deshalb
|
||||
# solche Pipes immer in einer Subshell ohne pipefail ausfuehren.
|
||||
if ( set +o pipefail; tar -tzf "$file" 2>/dev/null | grep -qx "$BUNDLE_DIRNAME/MANIFEST" ); then
|
||||
B_IS_BUNDLE=1
|
||||
local mf; mf="$(mktemp)"
|
||||
tar -xzOf "$file" "$BUNDLE_DIRNAME/MANIFEST" >"$mf"
|
||||
@@ -324,7 +332,7 @@ bundle_verify() {
|
||||
# Nutzdaten (omd-Archiv) aus einem Bundle nach stdout schreiben
|
||||
bundle_extract_payload() {
|
||||
local file="$1"
|
||||
if tar -tzf "$file" 2>/dev/null | grep -qx "$BUNDLE_DIRNAME/site.tar.gz"; then
|
||||
if ( set +o pipefail; tar -tzf "$file" 2>/dev/null | grep -qx "$BUNDLE_DIRNAME/site.tar.gz" ); then
|
||||
tar -xzOf "$file" "$BUNDLE_DIRNAME/site.tar.gz"
|
||||
else
|
||||
cat "$file"
|
||||
@@ -413,8 +421,8 @@ image_load_file() {
|
||||
[ -f "$file" ] || die "Datei nicht gefunden: $file"
|
||||
|
||||
# Ist das ueberhaupt ein Container-Image-Archiv (docker-archive/OCI)?
|
||||
if ! tar -tzf "$file" 2>/dev/null | grep -qE '^(manifest\.json|oci-layout|index\.json)$'; then
|
||||
if tar -tf "$file" 2>/dev/null | grep -qE '^(manifest\.json|oci-layout|index\.json)$'; then
|
||||
if ! ( set +o pipefail; tar -tzf "$file" 2>/dev/null | grep -qE '^(manifest\.json|oci-layout|index\.json)$' ); then
|
||||
if ( set +o pipefail; tar -tf "$file" 2>/dev/null | grep -qE '^(manifest\.json|oci-layout|index\.json)$' ); then
|
||||
:
|
||||
else
|
||||
err "'$file' enthaelt kein manifest.json / oci-layout."
|
||||
@@ -547,7 +555,7 @@ archive_docker_file() { # edition version -> Dateiname auf stdout
|
||||
[ -n "$names" ] || return 1
|
||||
local ed
|
||||
for ed in $(edition_aliases "$edition"); do
|
||||
if printf '%s\n' "$names" | grep -qx "check-mk-${ed}-docker-${version}.tar.gz"; then
|
||||
if ( set +o pipefail; printf '%s\n' "$names" | grep -qx "check-mk-${ed}-docker-${version}.tar.gz" ); then
|
||||
printf 'check-mk-%s-docker-%s.tar.gz\n' "$ed" "$version"; return 0
|
||||
fi
|
||||
done
|
||||
@@ -648,11 +656,8 @@ EOF
|
||||
log "Hole Image: $ref"
|
||||
if ! $RUNTIME pull "$ref"; then
|
||||
err "Das Image '$ref' konnte nicht geholt werden."
|
||||
if [ "$reg" != "docker.io" ] && [ -n "$user" ]; then
|
||||
warn "Die Anmeldung hat geklappt, der Pfad oder das Tag aber nicht.
|
||||
Ich sehe nach, was diese Registry tatsaechlich anbietet ..."
|
||||
image_cmd_repos --edition "$edition" --registry "$reg" \
|
||||
--user "$user" --password "$pass" || true
|
||||
if [ "$reg" != "docker.io" ] || [ -n "$user" ]; then
|
||||
image_diagnose_ref "$ref" || true
|
||||
return 1
|
||||
fi
|
||||
if [ "$edition" = enterprise ]; then
|
||||
@@ -1215,6 +1220,88 @@ image_cmd_test() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# Warum laesst sich eine Image-Referenz nicht holen?
|
||||
#
|
||||
# Die Fehlermeldungen der Runtime sind eindeutig, aber unerklaert:
|
||||
# "manifest unknown" -> Repository ist da, das TAG nicht
|
||||
# "repository name unknown" -> Repository gibt es nicht
|
||||
# "unauthorized" -> Anmeldung oder Berechtigung
|
||||
# Diese Funktion fragt die Registry direkt und sagt, welcher Fall vorliegt.
|
||||
image_diagnose_ref() { # ref
|
||||
local ref="$1"
|
||||
command -v curl >/dev/null 2>&1 || return 0
|
||||
|
||||
local tag regpart reg repo api
|
||||
tag="${ref##*:}"; regpart="${ref%:*}"
|
||||
case "$regpart" in
|
||||
*/*) reg="${regpart%%/*}"; repo="${regpart#*/}" ;;
|
||||
*) reg="docker.io"; repo="$regpart" ;;
|
||||
esac
|
||||
[ "$tag" = "$ref" ] && tag=""
|
||||
api="$(registry_api_host "$reg")"
|
||||
|
||||
local u="" p=""
|
||||
case "$reg" in
|
||||
docker.io|index.docker.io|registry-1.docker.io) : ;;
|
||||
*) u="${CMK_REGISTRY_USER:-}"; p="${CMK_REGISTRY_PASSWORD:-}" ;;
|
||||
esac
|
||||
|
||||
printf '\n%sWoran liegt es?%s\n' "$C_BLD" "$C_RST"
|
||||
printf ' Registry : %s\n' "$reg"
|
||||
printf ' Repository : %s\n' "$repo"
|
||||
printf ' Tag : %s\n\n' "${tag:-<keins>}"
|
||||
|
||||
local line code
|
||||
line="$(registry_repo_status "$api" "$repo" "$u" "$p")"
|
||||
code="${line%% *}"
|
||||
case "$code" in
|
||||
401|403)
|
||||
test_result fail "Anmeldung oder Berechtigung (HTTP $code)"
|
||||
printf ' Pruefen: %s image test --only registry\n' "$SELF"
|
||||
return 1 ;;
|
||||
404)
|
||||
test_result fail "Dieses Repository gibt es dort nicht (HTTP 404)"
|
||||
printf ' Welche es gibt: %s image repos --edition %s\n' "$SELF" "${CMK_EDITION:-enterprise}"
|
||||
return 1 ;;
|
||||
200) : ;;
|
||||
*) test_result warn "Registry antwortet unerwartet (HTTP $code)"; return 1 ;;
|
||||
esac
|
||||
|
||||
test_result ok "Repository vorhanden und zugaenglich"
|
||||
|
||||
local -a tags=()
|
||||
mapfile -t tags < <(registry_tags "$api" "$repo" "$u" "$p" | sed '/^$/d')
|
||||
if [ ${#tags[@]} -eq 0 ]; then
|
||||
test_result warn "Es liess sich keine Tag-Liste lesen."
|
||||
return 1
|
||||
fi
|
||||
if ( set +o pipefail; printf '%s\n' "${tags[@]}" | grep -qxF "$tag" ); then
|
||||
test_result ok "Das Tag '$tag' ist vorhanden - der Fehler hat eine andere Ursache."
|
||||
return 0
|
||||
fi
|
||||
|
||||
test_result fail "Das Tag '$tag' gibt es in diesem Repository NICHT."
|
||||
printf ' Genau das meint die Meldung "manifest unknown".\n\n'
|
||||
|
||||
# Naheliegende Tags zeigen: gleicher Zweig, sonst die neuesten
|
||||
local branch="${tag%%p*}"
|
||||
local -a near=()
|
||||
mapfile -t near < <(printf '%s\n' "${tags[@]}" | grep -F "$branch" | sort -rV | head -n 12)
|
||||
if [ ${#near[@]} -gt 0 ]; then
|
||||
printf ' %sVorhanden im Zweig %s%s\n' "$C_BLD" "$branch" "$C_RST"
|
||||
else
|
||||
mapfile -t near < <(printf '%s\n' "${tags[@]}" | sort -rV | head -n 12)
|
||||
printf ' %sVorhanden (neueste)%s\n' "$C_BLD" "$C_RST"
|
||||
fi
|
||||
printf ' %s\n' "${near[@]}"
|
||||
printf '\n Uebernehmen mit:\n'
|
||||
printf ' %s image use %s/%s:<tag> --remember\n' "$SELF" "$reg" "$repo"
|
||||
printf ' %s up\n' "$SELF"
|
||||
printf '\n Alle Tags: %s image versions --source registry --edition %s --all\n\n' \
|
||||
"$SELF" "${CMK_EDITION:-enterprise}"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# image versions - verfuegbare Versionen auflisten
|
||||
#
|
||||
@@ -1517,8 +1604,9 @@ cmd_image() {
|
||||
test|check) image_cmd_test "$@" ;;
|
||||
versions|tags) image_cmd_versions "$@" ;;
|
||||
repos|repo) image_cmd_repos "$@" ;;
|
||||
why|diagnose) image_diagnose_ref "${1:-${CMK_IMAGE:-}}" ;;
|
||||
*) die "Unbekanntes Unterkommando 'image $sub'.
|
||||
Moeglich: status | list | versions | repos | test | pull | download | load | use" ;;
|
||||
Moeglich: status | list | versions | repos | why | test | pull | download | load | use" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -1544,7 +1632,15 @@ cmd_up() {
|
||||
else
|
||||
log "Starte Stack (${RUNTIME}) - ohne NGINX Proxy Manager (NPM_ENABLED=off) ..."
|
||||
fi
|
||||
compose up -d "${svc[@]}"
|
||||
if ! compose up -d "${svc[@]}"; then
|
||||
echo
|
||||
err "Der Stack konnte nicht gestartet werden."
|
||||
# Haeufigste Ursache: das Image laesst sich nicht holen.
|
||||
if [ -n "${CMK_IMAGE:-}" ] && ! image_exists_local "$CMK_IMAGE"; then
|
||||
image_diagnose_ref "$CMK_IMAGE" || true
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
npm_enabled || npm_teardown_container
|
||||
ok "Stack gestartet."
|
||||
cmd_status
|
||||
@@ -2177,7 +2273,7 @@ do_restore() {
|
||||
if [ -n "$B_CMK_VERSION" ]; then
|
||||
local installed
|
||||
installed="$(cmk_versions_installed)"
|
||||
if ! printf '%s\n' "$installed" | grep -qxF "$B_CMK_VERSION"; then
|
||||
if ! ( set +o pipefail; printf '%s\n' "$installed" | grep -qxF "$B_CMK_VERSION" ); then
|
||||
err "Die Checkmk-Version des Backups ist im Container nicht installiert."
|
||||
printf ' benoetigt : %s\n' "$B_CMK_VERSION"
|
||||
printf ' installiert : %s\n' "$(printf '%s' "$installed" | tr '\n' ' ')"
|
||||
@@ -2551,7 +2647,7 @@ EOF
|
||||
|
||||
port_in_use() {
|
||||
command -v ss >/dev/null 2>&1 || return 1
|
||||
ss -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]$1\$"
|
||||
( set +o pipefail; ss -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]$1\$" )
|
||||
}
|
||||
|
||||
valid_port() {
|
||||
@@ -3300,7 +3396,7 @@ cmd_proxy() {
|
||||
local all; all="$(npm_api GET /api/nginx/proxy-hosts)"
|
||||
local i
|
||||
for i in $(json_ids "$all"); do
|
||||
if npm_api GET "/api/nginx/proxy-hosts/$i" | grep -qF "\"$dom\""; then pid="$i"; break; fi
|
||||
if ( set +o pipefail; npm_api GET "/api/nginx/proxy-hosts/$i" | grep -qF "\"$dom\"" ); then pid="$i"; break; fi
|
||||
done
|
||||
[ -n "$pid" ] || die "Kein Proxy-Host fuer '$dom' gefunden."
|
||||
fi
|
||||
@@ -3804,7 +3900,7 @@ gui_job_edit() { # name (leer = neu)
|
||||
while IFS= read -r sname; do
|
||||
[ -n "$sname" ] || continue
|
||||
items+=("$sname" "einzelne Site" \
|
||||
"$(printf '%s' ",$sites," | grep -q ",$sname," && echo on || echo off)")
|
||||
"$( ( set +o pipefail; printf '%s' ",$sites," | grep -q ",$sname," ) && echo on || echo off)")
|
||||
done < <(cmk_sites)
|
||||
local chosen
|
||||
chosen="$(ui_checklist "Sites" "Was soll dieser Job sichern?\n(ALL schliesst alle anderen ein)" "${items[@]}")" || return 0
|
||||
@@ -4822,7 +4918,30 @@ cmd_selftest() {
|
||||
printf ' "set -e" das Skript. Besser als if-Block schreiben.\n'
|
||||
fi
|
||||
|
||||
printf '\n%s5. Zeichensatz fuer die Oberflaeche%s\n' "$C_BLD" "$C_RST"
|
||||
printf '\n%s5. Keine "| grep -q" ohne Schutz vor SIGPIPE%s\n' "$C_BLD" "$C_RST"
|
||||
n=0
|
||||
for f in "${files[@]}"; do
|
||||
[ -f "$f" ] || continue
|
||||
while IFS= read -r line; do
|
||||
[ -n "$line" ] || continue
|
||||
printf ' %s[FEHLER]%s %s:%s\n' "$C_RED" "$C_RST" "$(basename "$f")" "$line"
|
||||
n=$((n+1))
|
||||
done < <(grep -nE '\|[[:space:]]*grep -[a-zA-Z]*q' "$f" \
|
||||
| grep -v 'set +o pipefail' \
|
||||
| grep -vE '^[0-9]+:[[:space:]]*#' \
|
||||
| grep -v 'printf' | cut -c1-72 || true)
|
||||
done
|
||||
if [ "$n" -eq 0 ]; then
|
||||
printf ' %s[ OK ]%s alle solchen Pipes laufen ohne pipefail\n' "$C_GRN" "$C_RST"
|
||||
else
|
||||
printf ' "grep -q" endet beim ersten Treffer; der Erzeuger bekommt\n'
|
||||
printf ' SIGPIPE und unter "set -o pipefail" gilt die Pipe als\n'
|
||||
printf ' fehlgeschlagen - abhaengig von der Datenmenge. Schreibweise:\n'
|
||||
printf ' if ( set +o pipefail; erzeuger | grep -q muster ); then\n'
|
||||
rc=1
|
||||
fi
|
||||
|
||||
printf '\n%s6. Zeichensatz fuer die Oberflaeche%s\n' "$C_BLD" "$C_RST"
|
||||
local before="${LC_ALL:-${LC_CTYPE:-${LANG:-<leer>}}}"
|
||||
ui_fix_locale || true
|
||||
printf ' Locale vorher : %s\n' "$before"
|
||||
@@ -4835,7 +4954,7 @@ cmd_selftest() {
|
||||
"$([ -n "${UI_LOCALE_NOTE:-}" ] && echo " (${UI_LOCALE_NOTE})")"
|
||||
fi
|
||||
|
||||
printf '\n%s6. Einstellungstabelle%s\n' "$C_BLD" "$C_RST"
|
||||
printf '\n%s7. Einstellungstabelle%s\n' "$C_BLD" "$C_RST"
|
||||
n="$(settings_defs | awk -F'|' 'NF!=6' | wc -l)"
|
||||
if [ "$n" -eq 0 ]; then
|
||||
printf ' %s[ OK ]%s alle Zeilen haben sechs Felder\n' "$C_GRN" "$C_RST"
|
||||
|
||||
@@ -168,7 +168,7 @@ cmk_sites() {
|
||||
}
|
||||
|
||||
cmk_site_exists() {
|
||||
cmk_sites | grep -qxF "$1"
|
||||
( set +o pipefail; cmk_sites | grep -qxF "$1" )
|
||||
}
|
||||
|
||||
cmk_site_version() {
|
||||
@@ -338,7 +338,7 @@ ui_fix_locale() {
|
||||
esac
|
||||
local l
|
||||
for l in C.UTF-8 C.utf8 en_US.UTF-8 en_US.utf8 de_DE.UTF-8 de_DE.utf8; do
|
||||
if locale -a 2>/dev/null | grep -qix "$l"; then
|
||||
if ( set +o pipefail; locale -a 2>/dev/null | grep -qix "$l" ); then
|
||||
# LC_ALL sticht jede einzelne Kategorie aus - solange es auf
|
||||
# einem Nicht-UTF-8-Wert steht, bliebe LC_CTYPE wirkungslos.
|
||||
if [ -n "${LC_ALL:-}" ]; then unset LC_ALL; fi
|
||||
|
||||
@@ -457,7 +457,7 @@ fi
|
||||
[ ${#SITES[@]} -gt 0 ] || die "Keine Site angegeben. --site SITE, --all oder --gui verwenden."
|
||||
|
||||
for s in "${SITES[@]}"; do
|
||||
list_sites | grep -qxF "$s" || die "Site '$s' existiert auf diesem Server nicht."
|
||||
( set +o pipefail; list_sites | grep -qxF "$s" ) || die "Site '$s' existiert auf diesem Server nicht."
|
||||
done
|
||||
|
||||
printf '\n%sZu sichernde Sites:%s %s\n' "$C_BLD" "$C_RST" "${SITES[*]}"
|
||||
|
||||
Reference in New Issue
Block a user