image repos: herausfinden, was die Registry wirklich anbietet

"Login Succeeded" und trotzdem "unable to copy from source": der
Repository-Pfad enterprise/check-mk-enterprise war geraten, nicht
belegt. Statt weiter zu raten fragt das Werkzeug jetzt nach.

  image repos [--edition E] [--registry R] [--user/--password]

fragt zuerst /v2/_catalog ab (sperren viele Registries) und probiert
danach die ueblichen Pfade durch, je Edition und deren Aliasnamen:
  <ed>/check-mk-<ed>, check-mk-<ed>, checkmk/check-mk-<ed>,
  enterprise/check-mk-<ed>
Gemeldet wird pro Pfad der HTTP-Status samt Tag-Anzahl. Scheitert ein
"image pull" gegen eine private Registry, laeuft die Pruefung von
selbst an und zeigt gleich, was dort liegt.

Wichtig bei der Deutung und deshalb auch so beschriftet: 401 heisst
nicht "vorhanden". Docker Hub antwortet auch auf nicht existierende
Repositories mit 401. Verlaesslich sind nur 200 und 404.

Nebenbei am Versionsarchiv geklaert, dass die Editionsumbenennung erst
mit 2.5 greift:
  2.4.0p9  -> check-mk-{raw,enterprise,cloud,managed}-docker-...
  2.5.0p13 -> check-mk-{community,pro,ultimate,ultimatemt}-docker-...
Fuer 2.4 ist "--edition enterprise" also richtig.

registry_get_token nimmt jetzt einen frei waehlbaren Scope, damit auch
registry:catalog:* angefordert werden kann.

Gegen Docker Hub verifiziert: findet checkmk/check-mk-raw (2394 Tags)
und checkmk/check-mk-community (534 Tags); gegen registry.checkmk.com
ohne Zugangsdaten sauberer Fehlbericht statt Haenger.

Dokumentiert als Abschnitt 8.8 in beiden Sprachfassungen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-20 17:19:54 +02:00
co-authored by Claude Opus 5
parent 7b26042fa4
commit f8a8c7a2a6
3 changed files with 212 additions and 6 deletions
+132 -4
View File
@@ -116,6 +116,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 repos [Opt.] herausfinden, welche Repositories die Registry
wirklich anbietet (Katalog + uebliche Pfade)
image test [Opt.] Zugangsdaten pruefen, ohne etwas herunterzuladen
--edition E Edition, deren Repository geprueft wird
--version V Version fuer die Pruefung des Downloadportals
@@ -607,6 +609,13 @@ 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
return 1
fi
if [ "$edition" = enterprise ]; then
cat >&2 <<'EOF'
@@ -1134,8 +1143,9 @@ image_cmd_test() {
# ---------------------------------------------------------------------
# Token fuer eine Registry besorgen ("" = anonym versuchen)
registry_get_token() { # api repo user pass -> Token auf stdout
local api="$1" repo="$2" user="$3" pass="$4"
registry_get_token() { # api repo user pass [scope] -> Token auf stdout
local api="$1" repo="$2" user="$3" pass="$4" scope="${5:-}"
[ -n "$scope" ] || scope="repository:$repo:pull"
local hdrf; hdrf="$(mktemp)"
curl -sS -o /dev/null -D "$hdrf" --max-time 30 "https://$api/v2/" >/dev/null 2>&1 || true
local wa realm service
@@ -1149,7 +1159,7 @@ registry_get_token() { # api repo user pass -> Token auf stdout
service="$(printf '%s' "$wa" | sed -n 's/.*service="\([^"]*\)".*/\1/p')"
[ -n "$realm" ] || return 0
local realm_host; realm_host="$(printf '%s' "$realm" | sed -E 's|^[a-z]+://([^/]+).*|\1|')"
local url="$realm?service=$service&scope=repository:$repo:pull"
local url="$realm?service=$service&scope=$scope"
local body netrc=""
if [ -n "$user" ]; then
netrc="$(netrc_make "$user" "$pass" "$api" "$realm_host")"
@@ -1198,6 +1208,123 @@ download_versions() { # user pass -> Versionsverzeichnisse
| sed -E 's|href="([^"/]+)/?"|\1|' | sort -u
}
# ---------------------------------------------------------------------
# Welches Repository heisst in der Registry wie?
#
# Der Pfad ist nicht zu erraten - "Login Succeeded" heisst noch lange
# nicht, dass enterprise/check-mk-enterprise existiert. Deshalb erst den
# Katalog fragen und, falls der gesperrt ist, die ueblichen Pfade
# durchprobieren. HTTP 404 = gibt es nicht, 401/403 = keine Berechtigung,
# 200 = nutzbar.
# ---------------------------------------------------------------------
registry_catalog() { # api user pass -> Repository-Namen
local api="$1" user="$2" pass="$3"
local token; token="$(registry_get_token "$api" "" "$user" "$pass" "registry:catalog:*")"
local -a a=(-sS --max-time 45)
if [ -n "$token" ]; then a+=(-H "Authorization: Bearer $token")
elif [ -n "$user" ]; then
local netrc; netrc="$(netrc_make "$user" "$pass" "$api")"; a+=(--netrc-file "$netrc")
fi
curl "${a[@]}" "https://$api/v2/_catalog?n=1000" 2>/dev/null \
| tr ',' '\n' | grep -oE '"[a-z0-9][a-z0-9._/-]*"' | tr -d '"' \
| grep -v '^repositories$' | sed '/^$/d' | sort -u
}
registry_repo_candidates() { # edition -> moegliche Repository-Pfade
local edition="$1" a
for a in $(edition_aliases "$edition"); do
printf '%s/check-mk-%s\n' "$a" "$a"
printf 'check-mk-%s\n' "$a"
printf 'checkmk/check-mk-%s\n' "$a"
printf 'enterprise/check-mk-%s\n' "$a"
done
}
# Status eines Repositories ermitteln: 200 / 401 / 403 / 404 / 000
registry_repo_status() { # api repo user pass -> "code anzahl_tags"
local api="$1" repo="$2" user="$3" pass="$4"
local token; token="$(registry_get_token "$api" "$repo" "$user" "$pass")"
local -a a=(-sS -o /tmp/.cmkrepo.$$ -w '%{http_code}' --max-time 30)
[ -n "$token" ] && a+=(-H "Authorization: Bearer $token")
local code
code="$(curl "${a[@]}" "https://$api/v2/$repo/tags/list" 2>/dev/null)" || code=000
local n=0
[ "${code:-000}" = 200 ] && n="$(tr ',' '\n' <"/tmp/.cmkrepo.$$" 2>/dev/null | grep -c '"' || echo 0)"
rm -f "/tmp/.cmkrepo.$$"
printf '%s %s\n' "${code:-000}" "$n"
}
image_cmd_repos() {
local edition="${CMK_EDITION:-enterprise}" reg="${CMK_REGISTRY:-registry.checkmk.com}"
local user="${CMK_REGISTRY_USER:-}" pass="${CMK_REGISTRY_PASSWORD:-}"
while [ $# -gt 0 ]; do
case "$1" in
--edition) edition="$2"; shift 2 ;;
--registry) reg="$2"; shift 2 ;;
--user) user="$2"; shift 2 ;;
--password) pass="$2"; shift 2 ;;
*) die "Unbekannte Option fuer 'image repos': $1" ;;
esac
done
command -v curl >/dev/null 2>&1 || die "Fuer 'image repos' wird curl benoetigt."
local api; api="$(registry_api_host "$reg")"
printf '\n%sRegistry %s%s\n' "$C_BLD" "$reg" "$C_RST"
[ -n "$user" ] || warn "Keine Zugangsdaten hinterlegt - ohne Anmeldung ist hier wenig zu sehen."
printf '\n%sKatalog (/v2/_catalog)%s\n' "$C_BLD" "$C_RST"
local -a cat=()
mapfile -t cat < <(registry_catalog "$api" "$user" "$pass" | grep -iE 'check|mk' | head -50)
if [ ${#cat[@]} -gt 0 ]; then
printf ' %s\n' "${cat[@]}"
else
printf ' (nicht abrufbar - viele Registries sperren den Katalog)\n'
fi
printf '\n%sUebliche Pfade fuer "%s" durchprobiert%s\n' "$C_BLD" "$edition" "$C_RST"
printf ' %-6s %-8s %s\n' "STATUS" "TAGS" "PFAD"
printf ' %s200 = nutzbar, 404 = gibt es nicht, 401/403 = kein Zugriff%s\n' "$C_BLU" "$C_RST"
local cand code n line ok=""
while IFS= read -r cand; do
[ -n "$cand" ] || continue
line="$(registry_repo_status "$api" "$cand" "$user" "$pass")"
code="${line%% *}"; n="${line##* }"
case "$code" in
200) printf ' %s%-6s%s %-8s %s\n' "$C_GRN" "$code" "$C_RST" "$n" "$cand"
[ -z "$ok" ] && ok="$cand" ;;
401|403) printf ' %s%-6s%s %-8s %s (kein Zugriff - oder gibt es nicht;\n%38sviele Registries verbergen das)\n' \
"$C_YEL" "$code" "$C_RST" "-" "$cand" "" ;;
404) printf ' %-6s %-8s %s (gibt es nicht)\n' "$code" "-" "$cand" ;;
*) printf ' %-6s %-8s %s\n' "${code:-000}" "-" "$cand" ;;
esac
done < <(registry_repo_candidates "$edition" | awk '!seen[$0]++')
echo
if [ -n "$ok" ]; then
ok "Nutzbar: $reg/$ok"
cat <<EOF
${C_BLD}Weiter${C_RST}
Tags ansehen : $SELF image versions --source registry --edition $edition
Image setzen : $SELF image use $reg/$ok:<version>
EOF
else
err "Unter '$reg' wurde kein nutzbares Repository fuer '$edition' gefunden."
cat <<EOF
Moegliche Gruende:
* Die Subskription schliesst den Registry-Zugang nicht ein.
Dann fuehrt der Tarball-Weg zum Ziel:
$SELF image download --edition $edition --version <version>
* Der Pfad heisst anders. Steht er im Kundenportal, laesst er sich
direkt setzen:
$SELF config set CMK_REGISTRY <registry>
$SELF image use <registry>/<pfad>:<version>
EOF
fi
echo
}
image_cmd_versions() {
local edition="${CMK_EDITION:-raw}" source="all" filter="" limit=25
local ruser="${CMK_REGISTRY_USER:-}" rpass="${CMK_REGISTRY_PASSWORD:-}"
@@ -1324,8 +1451,9 @@ cmd_image() {
use|set) image_cmd_use "$@" ;;
test|check) image_cmd_test "$@" ;;
versions|tags) image_cmd_versions "$@" ;;
repos|repo) image_cmd_repos "$@" ;;
*) die "Unbekanntes Unterkommando 'image $sub'.
Moeglich: status | list | versions | test | pull | download | load | use" ;;
Moeglich: status | list | versions | repos | test | pull | download | load | use" ;;
esac
}