From 4d2e234c36915e4af2abc1bbb45199f990a5e933 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 20 Sep 2026 19:00:04 +0200 Subject: [PATCH] Bezugsweg als Schalter, schlankes "Image holen", up holt selbst Drei zusammenhaengende Vereinfachungen aus der Bedienung heraus: 1. CMK_IMAGE_SOURCE bestimmt, woher ein fehlendes Image kommt: auto erst Registry, dann Downloadportal (Vorgabe) registry nur Registry download nur Tarball "auto" ist die sinnvolle Vorgabe, weil Registries nur die juengsten Patchstaende vorhalten - genau die aeltere Version, die eine Migration braucht, liegt dann nur noch im Archiv. Der Wechsel geschieht ohne Rueckfrage. 2. "image get" holt ueber diesen Weg, ohne dass Edition und Version erneut abgefragt werden. Im Menue fragt "Image holen" entsprechend nur noch nach dem Bezugsweg; der eingestellte ist gekennzeichnet. Der vollstaendige Assistent bleibt als eigener Punkt daneben, fuer den Fall, dass Edition oder Version geaendert werden sollen. 3. "up" beschafft ein lokal fehlendes Image selbst, bevor compose startet. Vorher lief compose in einen nackten Pull, der bei einer nur im Downloadportal vorhandenen Version scheitern musste - genau der Fall mit 2.4.0p9. Mit "up --no-fetch" bleibt das aus. Durchgespielt mit einer absichtlich nicht existierenden Version: up erkennt das fehlende Image, versucht die Registry, weicht auf das Downloadportal aus, bricht nach beiden Fehlschlaegen ab - und ruft compose gar nicht erst auf. Mit --no-fetch geht es direkt zu compose. Nebenbei: im Auswahlmenue erschien der eingestellte Bezugsweg doppelt (einmal als "wie eingestellt", einmal unter seinem Namen) - zwei Eintraege mit derselben Kennung. Jetzt wird der eingestellte nur noch gekennzeichnet. Co-Authored-By: Claude Opus 5 (1M context) --- .env.example | 9 +++ README.md | 46 +++++++++++- README_en.md | 45 +++++++++++- scripts/cmk-manage.sh | 164 ++++++++++++++++++++++++++++++++++++++++-- scripts/lib/common.sh | 1 + 5 files changed, 255 insertions(+), 10 deletions(-) diff --git a/.env.example b/.env.example index 76bd2ad..ad24036 100644 --- a/.env.example +++ b/.env.example @@ -53,6 +53,15 @@ CMK_EDITION=raw # angegeben werden (z.B. 2.3.0p23), "-latest" funktioniert dort nicht. CMK_VERSION=2.3.0-latest +# Woher soll das Image geholt werden, wenn es lokal fehlt? +# auto erst Registry, dann Downloadportal (Vorgabe) +# registry nur aus der Registry +# download nur als Tarball vom Downloadportal +# Hintergrund: Registries halten meist nur die juengsten Patchstaende +# vor. Eine aeltere Version - etwa die einer zu migrierenden Site - +# liegt dann nur noch im Downloadportal. +CMK_IMAGE_SOURCE=auto + # --- Bezugsweg 1: private Registry (Enterprise) ---------------------- # Zugangsdaten aus dem Checkmk-Kundenportal (portal.checkmk.com) CMK_REGISTRY=registry.checkmk.com diff --git a/README.md b/README.md index afe4abb..b8482f8 100644 --- a/README.md +++ b/README.md @@ -543,6 +543,7 @@ Die wichtigsten Schalter: | `CMK_RUNTIME` | leer = automatische Erkennung, sonst `docker` oder `podman` | | `CMK_IMAGE` | **das tatsaechlich verwendete Image**, immer vollqualifiziert – siehe [Kapitel 8](#8-checkmk-image-beschaffen-raw-enterprise--co) | | `CMK_EDITION`, `CMK_VERSION` | nur Vorgaben fuer den Image-Downloader | +| `CMK_IMAGE_SOURCE` | `auto`/`registry`/`download` – woher das Image geholt wird | | `CMK_REGISTRY_USER/-PASSWORD` | Anmeldung an `registry.checkmk.com` (Enterprise) | | `CMK_DOWNLOAD_USER/-PASSWORD` | Anmeldung am Checkmk-Downloadportal | | `CMK_SITE_ID` | Site, die der Container anlegt bzw. beim Start hochfährt | @@ -836,7 +837,47 @@ In der Oberfläche gibt es den Punkt **image → „Verfügbare Versionen auflisten"**; beim Holen eines Images muss die Version ohnehin nicht mehr abgetippt werden – dort erscheint eine Auswahlliste. -### 8.6 Image holen – drei Wege +### 8.6 Image holen – ein Kommando, drei Wege + +Stehen Edition und Version fest, genügt: + +```bash +sudo ./scripts/cmk-manage.sh image get +``` + +Woher geholt wird, steuert **`CMK_IMAGE_SOURCE`**: + +| Wert | Wirkung | +|---|---| +| `auto` (Vorgabe) | erst die Registry, dann das Downloadportal | +| `registry` | nur aus der Registry | +| `download` | nur als Tarball vom Downloadportal | + +Einmalig abweichen: `image get --source download`. + +`auto` ist die sinnvolle Vorgabe, weil Registries nur die jüngsten Patchstände +vorhalten – eine ältere, für eine Migration nötige Version liegt dann nur noch +im Downloadportal. Der Wechsel geschieht automatisch, ohne Rückfrage. + +**Beim `up` wird automatisch geholt.** Fehlt das Image lokal und sind Edition +und Version gesetzt, beschafft `up` es zuerst über diesen Weg – sonst versucht +compose einen nackten Pull, der bei einer nur im Archiv vorhandenen Version +scheitern muss: + +``` +[ INFO ] Das Image ist lokal nicht vorhanden - hole es (auto) ... +[ INFO ] Bezugsweg 'auto': zuerst die Registry ... +[ WARN ] Aus der Registry nicht zu bekommen - versuche das Downloadportal. +``` + +Mit `up --no-fetch` bleibt das aus. + +In der Oberfläche liegt das unter **image → „Image holen"**. Dort wird nur noch +der Bezugsweg abgefragt – der eingestellte ist gekennzeichnet. Wer Edition oder +Version ändern will, wählt dort **„Etwas anderes waehlen"** oder gleich den +Assistenten. + +#### Die Einzelschritte > **In der Oberfläche geht das als Assistent:** **image → „Image beschaffen"** > führt in einem Durchgang durch Edition, Version und Bezugsweg, setzt danach @@ -1931,7 +1972,7 @@ Eine Dateiauswahl mit Verzeichnisnavigation ist eingebaut. | Kommando | Wirkung | |---|---| -| `up` / `down` / `restart` / `pull` | Stack steuern | +| `up [--no-fetch]` / `down` / `restart` / `pull` | Stack steuern; `up` holt ein fehlendes Image selbst | | `status` | Container, Sites, Zugangsadressen | | `logs [-f]` | Container-Logs | | `sites` | Sites im Container auflisten | @@ -1942,6 +1983,7 @@ Eine Dateiauswahl mit Verzeichnisnavigation ist eingebaut. | `job list\|add\|set\|del\|run\|auto` | geplante Backups (eigene Zielpfade je Job) | | `restore …` | Backup zurückspielen | | `import …` | Migrations-Bundle einspielen | +| `image get` | Image über den eingestellten Bezugsweg holen | | `image status\|list\|versions\|repos\|why\|test\|pull\|download\|load\|use` | Checkmk-Image beschaffen, auswählen und Fehler erklären | | `browser [--engine …]` | Terminal-Browser im Container – Proxy Manager lokal bedienen | | `config list\|get\|set\|edit` | Einstellungen der `.env` anzeigen und ändern | diff --git a/README_en.md b/README_en.md index 2638c9b..7885b23 100644 --- a/README_en.md +++ b/README_en.md @@ -546,6 +546,7 @@ The most important settings: | `CMK_RUNTIME` | empty = auto-detect, otherwise `docker` or `podman` | | `CMK_IMAGE` | **the image actually used**, always fully qualified – see [chapter 8](#8-obtaining-the-checkmk-image-raw-enterprise--co) | | `CMK_EDITION`, `CMK_VERSION` | inputs for the image downloader only | +| `CMK_IMAGE_SOURCE` | `auto`/`registry`/`download` – where the image is fetched from | | `CMK_REGISTRY_USER/-PASSWORD` | login for `registry.checkmk.com` (Enterprise) | | `CMK_DOWNLOAD_USER/-PASSWORD` | login for the Checkmk download portal | | `CMK_SITE_ID` | the site the container creates and starts | @@ -842,7 +843,46 @@ In the interface there is **image → "Verfügbare Versionen auflisten"**; and when fetching an image the version no longer has to be typed at all – a selection list appears instead. -### 8.6 Fetching the image – three ways +### 8.6 Fetching the image – one command, three routes + +Once edition and version are set, this is enough: + +```bash +sudo ./scripts/cmk-manage.sh image get +``` + +Where it fetches from is controlled by **`CMK_IMAGE_SOURCE`**: + +| Value | Effect | +|---|---| +| `auto` (default) | registry first, then the download portal | +| `registry` | registry only | +| `download` | tarball from the download portal only | + +Deviate once with `image get --source download`. + +`auto` is the sensible default because registries only keep the most recent +patch levels – an older version needed for a migration then only exists in the +download portal. The switch happens automatically, without asking. + +**`up` fetches automatically.** If the image is missing locally and edition and +version are set, `up` obtains it first through this route – otherwise compose +attempts a plain pull, which must fail for a version that only exists in the +archive: + +``` +[ INFO ] Das Image ist lokal nicht vorhanden - hole es (auto) ... +[ INFO ] Bezugsweg 'auto': zuerst die Registry ... +[ WARN ] Aus der Registry nicht zu bekommen - versuche das Downloadportal. +``` + +`up --no-fetch` suppresses it. + +In the interface this is under **image → "Image holen"**. Only the source is +asked for there – the configured one is marked. To change edition or version, +pick **"Etwas anderes waehlen"** or the wizard directly. + +#### The individual steps > **In the interface this is a wizard:** **image → "Image beschaffen"** walks > through edition, version and source in one go, then sets `CMK_EDITION`, @@ -1930,7 +1970,7 @@ A file chooser with directory navigation is built in. | Command | Effect | |---|---| -| `up` / `down` / `restart` / `pull` | control the stack | +| `up [--no-fetch]` / `down` / `restart` / `pull` | control the stack; `up` fetches a missing image itself | | `status` | containers, sites, access addresses | | `logs [-f]` | container logs | | `sites` | list the sites in the container | @@ -1941,6 +1981,7 @@ A file chooser with directory navigation is built in. | `job list\|add\|set\|del\|run\|auto` | scheduled backups (own target path per job) | | `restore …` | restore a backup | | `import …` | import a migration bundle | +| `image get` | fetch the image via the configured route | | `image status\|list\|versions\|repos\|why\|test\|pull\|download\|load\|use` | obtain and select the Checkmk image, and explain failures | | `browser [--engine …]` | terminal browser in a container – operate the Proxy Manager locally | | `config list\|get\|set\|edit` | show and change settings in `.env` | diff --git a/scripts/cmk-manage.sh b/scripts/cmk-manage.sh index 5636fcd..3a15e5b 100755 --- a/scripts/cmk-manage.sh +++ b/scripts/cmk-manage.sh @@ -43,7 +43,9 @@ KOMMANDOS - Oberflaeche gui | menu ncurses-Oberflaeche starten (dialog/whiptail) KOMMANDOS - Stack - up Stack starten (compose up -d) + up [--no-fetch] Stack starten (compose up -d). Fehlt das Image + lokal, wird es zuvor ueber CMK_IMAGE_SOURCE geholt; + --no-fetch unterdrueckt das down Stack stoppen und Container entfernen restart Stack neu starten pull Images aktualisieren @@ -128,6 +130,10 @@ KOMMANDOS - Checkmk-Image beschaffen --version V Version fuer die Pruefung des Downloadportals --user U --password P statt der Werte aus der .env --only registry|download nur einen Bezugsweg pruefen + image get [Opt.] Image ueber den eingestellten Bezugsweg holen + --source registry|download|auto (Vorgabe: CMK_IMAGE_SOURCE) + auto = erst Registry, dann Downloadportal + --edition E --version V sonst aus der .env image pull [Opt.] Image aus einer Registry holen --edition E raw|community|free|cloud|managed|pro|ultimate| ultimatemt|enterprise (Vorgabe: CMK_EDITION) @@ -656,6 +662,7 @@ EOF log "Hole Image: $ref" if ! $RUNTIME pull "$ref"; then err "Das Image '$ref' konnte nicht geholt werden." + if [ -n "${IMAGE_QUIET_FAIL:-}" ]; then return 1; fi if [ "$reg" != "docker.io" ] || [ -n "$user" ]; then image_diagnose_ref "$ref" || true return 1 @@ -1329,6 +1336,67 @@ EOF return 1 } +# --------------------------------------------------------------------- +# Image holen - ueber den eingestellten Bezugsweg +# +# CMK_IMAGE_SOURCE bestimmt, woher: +# registry nur aus der Registry +# download nur als Tarball vom Downloadportal +# auto erst Registry, dann Tarball (Vorgabe) +# +# "auto" ist die sinnvolle Vorgabe, weil Registries nur die juengsten +# Patchstaende vorhalten. Eine aeltere, fuer eine Migration noetige +# Version liegt dann nur noch im Downloadportal. +# --------------------------------------------------------------------- +image_source_default() { + case "$(printf '%s' "${CMK_IMAGE_SOURCE:-auto}" | tr 'A-Z' 'a-z')" in + registry|reg|r) printf 'registry\n' ;; + download|dl|tarball|d) printf 'download\n' ;; + *) printf 'auto\n' ;; + esac +} + +image_cmd_get() { + local edition="${CMK_EDITION:-}" version="${CMK_VERSION:-}" src="" + local -a extra=() + while [ $# -gt 0 ]; do + case "$1" in + --edition) edition="$2"; shift 2 ;; + --version) version="$2"; shift 2 ;; + --source) src="$2"; shift 2 ;; + --user) extra+=(--user "$2"); shift 2 ;; + --password) extra+=(--password "$2"); shift 2 ;; + *) die "Unbekannte Option fuer 'image get': $1" ;; + esac + done + [ -n "$src" ] || src="$(image_source_default)" + case "$src" in registry|download|auto) : ;; + *) die "--source: registry | download | auto" ;; esac + [ -n "$edition" ] || die "Keine Edition eingestellt (CMK_EDITION oder --edition)." + [ -n "$version" ] || die "Keine Version eingestellt (CMK_VERSION oder --version)." + + case "$src" in + registry) + image_cmd_pull --edition "$edition" --version "$version" --remember ${extra[@]+"${extra[@]}"} ;; + download) + image_cmd_download --edition "$edition" --version "$version" --remember ${extra[@]+"${extra[@]}"} ;; + auto) + log "Bezugsweg 'auto': zuerst die Registry ..." + if IMAGE_QUIET_FAIL=1 image_cmd_pull --edition "$edition" --version "$version" \ + --remember ${extra[@]+"${extra[@]}"}; then + return 0 + fi + warn "Aus der Registry nicht zu bekommen - versuche das Downloadportal." + if image_cmd_download --edition "$edition" --version "$version" \ + --remember ${extra[@]+"${extra[@]}"}; then + return 0 + fi + err "Weder Registry noch Downloadportal haben geliefert." + image_diagnose_ref "$(edition_repo "$edition"):$version" || true + return 1 ;; + esac +} + # --------------------------------------------------------------------- # image versions - verfuegbare Versionen auflisten # @@ -1632,8 +1700,9 @@ cmd_image() { versions|tags) image_cmd_versions "$@" ;; repos|repo) image_cmd_repos "$@" ;; why|diagnose) image_diagnose_ref "${1:-${CMK_IMAGE:-}}" ;; + get|fetch) image_cmd_get "$@" ;; *) die "Unbekanntes Unterkommando 'image $sub'. - Moeglich: status | list | versions | repos | why | test | pull | download | load | use" ;; + Moeglich: status | list | versions | repos | why | test | get | pull | download | load | use" ;; esac } @@ -1659,6 +1728,20 @@ cmd_up() { else log "Starte Stack (${RUNTIME}) - ohne NGINX Proxy Manager (NPM_ENABLED=off) ..." fi + # Fehlt das Image lokal, es selbst holen - ueber den eingestellten + # Bezugsweg. Sonst versucht compose einen nackten Pull, der bei einer + # nur im Downloadportal vorhandenen Version scheitern muss. + if [ -z "${UP_NO_FETCH:-}" ] && [ -n "${CMK_IMAGE:-}" ] \ + && ! image_exists_local "$CMK_IMAGE" \ + && [ -n "${CMK_EDITION:-}" ] && [ -n "${CMK_VERSION:-}" ]; then + log "Das Image ist lokal nicht vorhanden - hole es ($(image_source_default)) ..." + if ! image_cmd_get; then + err "Das Image konnte nicht beschafft werden - der Stack wird nicht gestartet." + return 1 + fi + load_env "${ENV_FILE:-$PROJECT_DIR/.env}" + fi + if ! compose up -d "${svc[@]}"; then echo err "Der Stack konnte nicht gestartet werden." @@ -2790,6 +2873,7 @@ runtime|TZ|text|Zeitzone|| image|CMK_IMAGE|info|VERWENDETES Image (setzt der Assistent)||1 image|CMK_EDITION|info|Edition (setzt der Assistent)||1 image|CMK_VERSION|info|Version (setzt der Assistent)||1 +image|CMK_IMAGE_SOURCE|choice|Bezugsweg beim Holen|auto:registry:download| image|CMK_REGISTRY|text|Registry fuer Enterprise||1 image|CMK_REGISTRY_USER|text|Registry-Benutzer||1 image|CMK_REGISTRY_PASSWORD|password|Registry-Kennwort||1 @@ -4077,7 +4161,8 @@ gui_image_menu() { Edition/Version: ${CMK_EDITION:-raw} / ${CMK_VERSION:-?}" \ status "Status und lokale Images anzeigen" \ versions "Verfuegbare Versionen auflisten" \ - holen "Image beschaffen (Assistent: Edition, Version, Bezugsweg)" \ + holen "Image holen (Registry oder Downloadportal)" \ + wizard "Assistent: Edition, Version und Bezugsweg waehlen" \ test "Zugangsdaten pruefen (Registry und Downloadportal)" \ use "Vorhandenes lokales Image auswaehlen" \ back "zurueck")" || return 0 @@ -4085,7 +4170,8 @@ Edition/Version: ${CMK_EDITION:-raw} / ${CMK_VERSION:-?}" \ status) local f; f="$(mktemp)"; NO_COLOR=1 cmd_image status >"$f" 2>&1 || true ui_text "Image-Status" "$f"; rm -f "$f" ;; versions) gui_image_versions || true ;; - holen) gui_image_wizard || true ;; + holen) gui_image_get || true ;; + wizard) gui_image_wizard || true ;; test) gui_image_test || true ;; use) gui_image_use || true ;; back) return 0 ;; @@ -4296,6 +4382,69 @@ Wirksam wird das mit 'Stack steuern -> Stack starten' (die Container werden dabei neu erstellt)." } +# Holen, wenn Edition und Version schon feststehen: nur noch die Frage +# nach dem Bezugsweg. Der volle Assistent bleibt als Wahlmoeglichkeit. +gui_image_get() { + if [ -z "${CMK_EDITION:-}" ] || [ -z "${CMK_VERSION:-}" ]; then + ui_msg "Erst Edition und Version" \ +"Es ist noch keine Edition bzw. Version eingestellt. + +Der Assistent fragt beides ab und laesst sich gleich +anschliessen." + gui_image_wizard || true + return 0 + fi + + local ref="" vorgabe + if edition_known "${CMK_EDITION}" 2>/dev/null; then + ref="$(edition_repo "$CMK_EDITION"):$CMK_VERSION" + fi + vorgabe="$(image_source_default)" + + # Der eingestellte Weg wird gekennzeichnet, statt ihn doppelt + # aufzufuehren - sonst gaebe es zwei Eintraege mit derselben Kennung. + local m_auto="erst Registry, dann Downloadportal" + local m_reg="nur aus der Registry" + local m_dl="nur als Tarball vom Downloadportal" + case "$vorgabe" in + auto) m_auto="$m_auto (eingestellt)" ;; + registry) m_reg="$m_reg (eingestellt)" ;; + download) m_dl="$m_dl (eingestellt)" ;; + esac + + local sel + sel="$(ui_menu "Image holen" \ +"Edition/Version: ${CMK_EDITION} / ${CMK_VERSION}${ref:+ +Registry-Referenz: $ref} + +Woher soll das Image geholt werden?" \ + auto "$m_auto" \ + registry "$m_reg" \ + download "$m_dl" \ + datei "Vorhandene Tarball-Datei einspielen" \ + assistent "Etwas anderes waehlen (Edition/Version aendern)")" || return 0 + + case "$sel" in + assistent) gui_image_wizard || true; return 0 ;; + datei) + local lf + lf="$(ui_pick_file "${IMAGE_DIR:-$PROJECT_DIR/images}" '*.tar.gz')" || return 0 + [ -n "$lf" ] || return 0 + ui_run "Image einspielen" bash -c \ + "cd '$PROJECT_DIR' && NO_COLOR=1 '$SELF' -y image load --file '$lf'" + load_env "${ENV_FILE:-$PROJECT_DIR/.env}" + return 0 ;; + esac + + ui_run "Image holen ($sel)" bash -c \ + "cd '$PROJECT_DIR' && NO_COLOR=1 '$SELF' -y image get --source '$sel'" + load_env "${ENV_FILE:-$PROJECT_DIR/.env}" + + local f; f="$(mktemp)" + NO_COLOR=1 cmd_image status >"$f" 2>&1 || true + ui_text "Stand nach dem Holen" "$f"; rm -f "$f" +} + gui_image_versions() { local ed ed="$(gui_image_pick_edition)" || return 0 @@ -4517,7 +4666,8 @@ gui_settings_category() { done < <(settings_defs) # Zusatzaktionen, die inhaltlich zur Kategorie gehoeren case "$cat" in - image) items+=("__wizard__" ">> Image beschaffen (Edition, Version, Bezugsweg)") + image) items+=("__get__" ">> Image jetzt holen (Registry oder Downloadportal)") + items+=("__wizard__" ">> Assistent: Edition, Version, Bezugsweg") items+=("__test__" ">> Zugangsdaten jetzt pruefen (Registry + Downloadportal)") ;; npm) items+=("__proxy__" ">> Proxy-Hosts anlegen/verwalten") items+=("__npm__" ">> Proxy Manager: Stand und Admin-Port anzeigen") ;; @@ -4528,6 +4678,7 @@ gui_settings_category() { sel="$(ui_menu "$title" "Eintrag waehlen und mit ENTER aendern:" "${items[@]}")" || return 0 case "$sel" in back) return 0 ;; + __get__) gui_image_get || true; continue ;; __wizard__) gui_image_wizard || true; continue ;; __proxy__) gui_proxy_menu || true; continue ;; __test__) gui_image_test || true; continue ;; @@ -5051,7 +5202,8 @@ main() { local cmd="${1:-gui}"; [ $# -gt 0 ] && shift || true case "$cmd" in gui|menu) gui_main ;; - up|start) cmd_up ;; + up|start) if [ "${1:-}" = "--no-fetch" ]; then UP_NO_FETCH=1; fi + cmd_up ;; down|stop) cmd_down ;; restart) cmd_restart || true ;; pull) cmd_pull || true ;; diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh index 65c85d0..72bf020 100644 --- a/scripts/lib/common.sh +++ b/scripts/lib/common.sh @@ -45,6 +45,7 @@ load_env() { CMK_IMAGE="${CMK_IMAGE:-docker.io/checkmk/check-mk-raw:2.3.0-latest}" NPM_ENABLED="${NPM_ENABLED:-on}" BACKUP_AUTO="${BACKUP_AUTO:-off}" + CMK_IMAGE_SOURCE="${CMK_IMAGE_SOURCE:-auto}" PROXY_FORWARD_HOST="${PROXY_FORWARD_HOST:-127.0.0.1}" PROXY_FORWARD_PORT="${PROXY_FORWARD_PORT:-5000}" NPM_ADMIN_PORT="${NPM_ADMIN_PORT:-81}"