1020 lines
39 KiB
Bash
Executable File
1020 lines
39 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# =====================================================================
|
|
# cmk-manage.sh
|
|
# Verwaltung des Checkmk-/NGINX-Proxy-Manager-Stacks:
|
|
# Stack-Steuerung, Backup, Restore und Import (Migration) von Sites.
|
|
#
|
|
# Zwei Bedienarten:
|
|
# 1) Parametergesteuert : ./scripts/cmk-manage.sh backup --site cmk
|
|
# 2) ncurses-Oberflaeche: ./scripts/cmk-manage.sh gui
|
|
#
|
|
# Backups/Bundles sind immer .tar.gz
|
|
# =====================================================================
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
SELF="$SCRIPT_DIR/cmk-manage.sh"
|
|
# shellcheck source=lib/common.sh
|
|
. "$SCRIPT_DIR/lib/common.sh"
|
|
|
|
BUNDLE_DIRNAME="cmkbundle"
|
|
ASSUME_YES=""
|
|
VERBOSE=""
|
|
ENVFILE_OPT=""
|
|
|
|
# =====================================================================
|
|
# Hilfe
|
|
# =====================================================================
|
|
usage() {
|
|
cat <<'EOF'
|
|
cmk-manage.sh - Checkmk Stack Manager (Docker & Podman)
|
|
|
|
AUFRUF
|
|
cmk-manage.sh [globale Optionen] <kommando> [Optionen]
|
|
|
|
GLOBALE OPTIONEN
|
|
--env-file DATEI abweichende .env verwenden
|
|
-y, --yes alle Rueckfragen automatisch mit "ja" beantworten
|
|
-v, --verbose ausfuehrliche Ausgabe
|
|
-h, --help diese Hilfe
|
|
|
|
KOMMANDOS - Oberflaeche
|
|
gui | menu ncurses-Oberflaeche starten (dialog/whiptail)
|
|
|
|
KOMMANDOS - Stack
|
|
up Stack starten (compose up -d)
|
|
down Stack stoppen und Container entfernen
|
|
restart Stack neu starten
|
|
pull Images aktualisieren
|
|
status Status von Containern und Sites anzeigen
|
|
logs [-f] [DIENST] Logs anzeigen
|
|
shell Root-Shell im Checkmk-Container
|
|
omd ARG... beliebiges omd-Kommando im Container ausfuehren
|
|
|
|
KOMMANDOS - Sites
|
|
sites Sites im Container auflisten
|
|
site-start SITE Site starten
|
|
site-stop SITE Site stoppen
|
|
start-all-sites alle vorhandenen Sites starten (fuer Autostart nach Reboot)
|
|
|
|
KOMMANDOS - Backup / Restore / Migration
|
|
backup [Optionen] Backup einer/aller Sites als .tar.gz-Bundle erzeugen
|
|
--site SITE Site (mehrfach moeglich)
|
|
--all alle Sites sichern
|
|
--dir VERZ Zielverzeichnis (Vorgabe: $BACKUP_DIR)
|
|
--label TEXT Freitext-Kennzeichnung im Dateinamen
|
|
--no-rrds Performance-Daten (RRDs) auslassen
|
|
--no-logs Logdateien auslassen
|
|
--stop Site waehrend des Backups stoppen (konsistenter)
|
|
|
|
list vorhandene Backups/Bundles auflisten
|
|
verify --file DATEI Bundle pruefen (Manifest + SHA256)
|
|
|
|
restore [Optionen] Backup wiederherstellen
|
|
--file DATEI Bundle oder rohes omd-Backup (.tar.gz)
|
|
--as-site NAME unter anderem Site-Namen wiederherstellen
|
|
(ACHTUNG: Agents muessen dann neu registriert werden!)
|
|
--reuse vorhandene Site ueberschreiben
|
|
--kill laufende Prozesse der Site beenden
|
|
--no-start Site nach dem Restore nicht starten
|
|
|
|
import [Optionen] Site von einer Direktinstallation uebernehmen
|
|
(Bundle aus migrate_creator.sh)
|
|
--file DATEI Migrations-Bundle (.tar.gz)
|
|
--reuse vorhandene Site ueberschreiben
|
|
--kill laufende Prozesse der Site beenden
|
|
--set-default-site CMK_SITE_ID in der .env auf die importierte Site setzen
|
|
--no-start Site nach dem Import nicht starten
|
|
|
|
prune --keep N nur die N neuesten Backups behalten
|
|
|
|
KOMMANDOS - Zertifikat
|
|
cert [Optionen] selbstsigniertes Zertifikat fuer den Proxy erzeugen
|
|
--domain FQDN Common Name / SAN
|
|
--alt NAME zusaetzlicher SAN (mehrfach; DNS-Name oder IP)
|
|
--days N Gueltigkeit in Tagen (Vorgabe 3650)
|
|
|
|
BEISPIELE
|
|
./scripts/cmk-manage.sh up
|
|
./scripts/cmk-manage.sh backup --all --no-logs
|
|
./scripts/cmk-manage.sh import --file backups/cmkmigrate_prod_2.3.0p23_*.tar.gz --set-default-site
|
|
./scripts/cmk-manage.sh gui
|
|
EOF
|
|
}
|
|
|
|
# =====================================================================
|
|
# Bundle-Format
|
|
#
|
|
# <name>.tar.gz
|
|
# cmkbundle/MANIFEST key=value, per "source" lesbar
|
|
# cmkbundle/INFO.txt menschenlesbare Zusammenfassung
|
|
# cmkbundle/site.tar.gz das eigentliche "omd backup"-Archiv
|
|
# cmkbundle/site.tar.gz.sha256
|
|
# =====================================================================
|
|
|
|
edition_from_version() {
|
|
case "$1" in
|
|
*.cre) echo "Raw Edition" ;;
|
|
*.cee) echo "Enterprise Edition" ;;
|
|
*.cme) echo "Managed Services Edition" ;;
|
|
*.cce) echo "Cloud Edition" ;;
|
|
*) echo "unbekannt" ;;
|
|
esac
|
|
}
|
|
|
|
# Manifest eines Bundles einlesen -> Variablen B_*
|
|
bundle_read() {
|
|
local file="$1"
|
|
B_SITE=""; B_CMK_VERSION=""; B_SOURCE_KIND=""; B_SOURCE_HOST=""
|
|
B_SOURCE_IP=""; B_CREATED=""; B_ARCHIVE_SHA256=""; B_LABEL=""
|
|
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
|
|
B_IS_BUNDLE=1
|
|
local mf; mf="$(mktemp)"
|
|
tar -xzOf "$file" "$BUNDLE_DIRNAME/MANIFEST" >"$mf"
|
|
# nur bekannte Schluessel uebernehmen (kein blindes eval)
|
|
local k v
|
|
while IFS='=' read -r k v; do
|
|
case "$k" in
|
|
SITE) B_SITE="$v" ;;
|
|
CMK_VERSION) B_CMK_VERSION="$v" ;;
|
|
SOURCE_KIND) B_SOURCE_KIND="$v" ;;
|
|
SOURCE_HOST) B_SOURCE_HOST="$v" ;;
|
|
SOURCE_IP) B_SOURCE_IP="$v" ;;
|
|
SOURCE_OS) B_SOURCE_OS="$v" ;;
|
|
CREATED) B_CREATED="$v" ;;
|
|
ARCHIVE_SHA256) B_ARCHIVE_SHA256="$v" ;;
|
|
ARCHIVE_SIZE) B_ARCHIVE_SIZE="$v" ;;
|
|
LABEL) B_LABEL="$v" ;;
|
|
BUNDLE_TYPE) B_BUNDLE_TYPE="$v" ;;
|
|
OMD_BACKUP_OPTS) B_OMD_BACKUP_OPTS="$v" ;;
|
|
esac
|
|
done <"$mf"
|
|
rm -f "$mf"
|
|
else
|
|
# rohes omd-Backup: Site-Name ist die erste Pfadkomponente.
|
|
# Ein omd-Archiv beginnt immer mit "<site>/..." - alles andere ist
|
|
# kein Checkmk-Backup und wird abgewiesen.
|
|
local first
|
|
first="$(tar -tzf "$file" 2>/dev/null | head -n1)"
|
|
case "$first" in
|
|
*/*) B_SITE="${first%%/*}" ;;
|
|
*) return 1 ;;
|
|
esac
|
|
B_BUNDLE_TYPE="raw"
|
|
B_SOURCE_KIND="unbekannt"
|
|
fi
|
|
[ -n "$B_SITE" ] || return 1
|
|
}
|
|
|
|
bundle_show() {
|
|
local file="$1"
|
|
bundle_read "$file" || { echo "Kein gueltiges Checkmk-Backup: $file"; return 1; }
|
|
cat <<EOF
|
|
Datei : $file
|
|
Groesse : $(human_size "$(file_size "$file")")
|
|
Typ : $([ "$B_IS_BUNDLE" = 1 ] && echo "Bundle (${B_BUNDLE_TYPE:-backup})" || echo "rohes omd-Backup")
|
|
Site : $B_SITE
|
|
Checkmk-Version: ${B_CMK_VERSION:-unbekannt} ($(edition_from_version "${B_CMK_VERSION:-x}"))
|
|
Quelle : ${B_SOURCE_KIND:-?} ${B_SOURCE_HOST:+/ $B_SOURCE_HOST}${B_SOURCE_IP:+ ($B_SOURCE_IP)}
|
|
Quell-OS : ${B_SOURCE_OS:-unbekannt}
|
|
Erstellt : ${B_CREATED:-unbekannt}
|
|
Kennzeichnung : ${B_LABEL:-keine}
|
|
omd-Optionen : ${B_OMD_BACKUP_OPTS:-keine}
|
|
EOF
|
|
}
|
|
|
|
bundle_verify() {
|
|
local file="$1"
|
|
[ -f "$file" ] || die "Datei nicht gefunden: $file"
|
|
log "Pruefe Archivstruktur ..."
|
|
tar -tzf "$file" >/dev/null || die "Archiv ist beschaedigt oder kein gueltiges tar.gz."
|
|
bundle_read "$file" || die "Im Archiv wurde keine Checkmk-Site gefunden."
|
|
if [ "$B_IS_BUNDLE" = 1 ] && [ -n "$B_ARCHIVE_SHA256" ]; then
|
|
log "Pruefe SHA256 der Nutzdaten ..."
|
|
local sum
|
|
sum="$(tar -xzOf "$file" "$BUNDLE_DIRNAME/site.tar.gz" | sha256sum | awk '{print $1}')"
|
|
[ "$sum" = "$B_ARCHIVE_SHA256" ] || die "Pruefsumme falsch!
|
|
erwartet : $B_ARCHIVE_SHA256
|
|
ermittelt: $sum"
|
|
ok "Pruefsumme korrekt."
|
|
else
|
|
warn "Kein Manifest/keine Pruefsumme vorhanden - nur Strukturpruefung."
|
|
fi
|
|
bundle_show "$file"
|
|
ok "Bundle ist in Ordnung."
|
|
}
|
|
|
|
# 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
|
|
tar -xzOf "$file" "$BUNDLE_DIRNAME/site.tar.gz"
|
|
else
|
|
cat "$file"
|
|
fi
|
|
}
|
|
|
|
# =====================================================================
|
|
# Stack-Kommandos
|
|
# =====================================================================
|
|
cmd_up() {
|
|
[ -f "$PROJECT_DIR/.env" ] || die "Keine .env vorhanden. Bitte: cp .env.example .env && \$EDITOR .env"
|
|
log "Starte Stack (${RUNTIME}) ..."
|
|
compose up -d
|
|
ok "Stack gestartet."
|
|
cmd_status
|
|
}
|
|
|
|
cmd_down() { log "Stoppe Stack ..."; compose down; ok "Stack gestoppt."; }
|
|
cmd_restart() { compose down || true; compose up -d; ok "Stack neu gestartet."; }
|
|
cmd_pull() { compose pull; ok "Images aktualisiert. Danach: $0 up"; }
|
|
cmd_logs() { compose logs "$@"; }
|
|
cmd_shell() { require_cmk_running; $RUNTIME exec -it "$CMK_CONTAINER_NAME" bash; }
|
|
cmd_omd() { require_cmk_running; $RUNTIME exec -it "$CMK_CONTAINER_NAME" omd "$@"; }
|
|
|
|
cmd_status() {
|
|
printf '\n%sContainer%s\n' "$C_BLD" "$C_RST"
|
|
local c
|
|
for c in "$CMK_CONTAINER_NAME" "$NPM_CONTAINER_NAME"; do
|
|
if container_exists "$c"; then
|
|
printf ' %-24s %s\n' "$c" \
|
|
"$(container_running "$c" && echo "${C_GRN}laeuft${C_RST}" || echo "${C_RED}gestoppt${C_RST}")"
|
|
else
|
|
printf ' %-24s %s\n' "$c" "${C_YEL}nicht vorhanden${C_RST}"
|
|
fi
|
|
done
|
|
|
|
if container_running "$CMK_CONTAINER_NAME"; then
|
|
printf '\n%sSites im Container%s\n' "$C_BLD" "$C_RST"
|
|
printf ' %-20s %-18s %s\n' "SITE" "VERSION" "STATUS"
|
|
local s
|
|
while IFS= read -r s; do
|
|
[ -n "$s" ] || continue
|
|
printf ' %-20s %-18s %s\n' "$s" "$(cmk_site_version "$s")" "$(cmk_site_state_text "$s")"
|
|
done < <(cmk_sites)
|
|
printf '\n Standard-Site laut .env : %s\n' "$CMK_SITE_ID"
|
|
fi
|
|
|
|
printf '\n%sZugang%s\n' "$C_BLD" "$C_RST"
|
|
local ip; ip="$(primary_ip)"
|
|
printf ' Checkmk (direkt) : http://%s:5000/%s/\n' "$ip" "$CMK_SITE_ID"
|
|
printf ' Checkmk (ueber Proxy) : https://<FQDN>/%s/\n' "$CMK_SITE_ID"
|
|
printf ' Agent-Receiver : %s:8000\n' "$ip"
|
|
printf ' NGINX Proxy Manager : http://%s:81/ (Erstlogin: admin@example.com / changeme)\n\n' "$ip"
|
|
}
|
|
|
|
# =====================================================================
|
|
# Site-Kommandos
|
|
# =====================================================================
|
|
cmd_sites() {
|
|
require_cmk_running
|
|
printf '%-20s %-18s %s\n' "SITE" "VERSION" "STATUS"
|
|
local s
|
|
while IFS= read -r s; do
|
|
[ -n "$s" ] || continue
|
|
printf '%-20s %-18s %s\n' "$s" "$(cmk_site_version "$s")" "$(cmk_site_state_text "$s")"
|
|
done < <(cmk_sites)
|
|
}
|
|
|
|
cmd_site_start() {
|
|
require_cmk_running
|
|
[ $# -ge 1 ] || die "Site-Name fehlt."
|
|
ct omd start "$1" && ok "Site '$1' gestartet."
|
|
}
|
|
|
|
cmd_site_stop() {
|
|
require_cmk_running
|
|
[ $# -ge 1 ] || die "Site-Name fehlt."
|
|
ct omd stop "$1" && ok "Site '$1' gestoppt."
|
|
}
|
|
|
|
# Wird vom systemd-Unit nach dem Start aufgerufen: alle Sites hochfahren.
|
|
# (Der Container-Entrypoint startet nur CMK_SITE_ID.)
|
|
cmd_start_all_sites() {
|
|
local tries=0
|
|
while ! container_running "$CMK_CONTAINER_NAME"; do
|
|
tries=$((tries+1)); [ "$tries" -gt 60 ] && die "Container '$CMK_CONTAINER_NAME' startet nicht."
|
|
sleep 2
|
|
done
|
|
# kurz warten, bis der Entrypoint durch ist
|
|
sleep 5
|
|
local s
|
|
while IFS= read -r s; do
|
|
[ -n "$s" ] || continue
|
|
if [ "$(cmk_site_state "$s")" != "0" ]; then
|
|
log "Starte Site '$s' ..."
|
|
ct omd start "$s" || warn "Site '$s' konnte nicht gestartet werden."
|
|
else
|
|
debug "Site '$s' laeuft bereits."
|
|
fi
|
|
done < <(cmk_sites)
|
|
ok "Alle Sites geprueft/gestartet."
|
|
}
|
|
|
|
# =====================================================================
|
|
# Backup
|
|
# =====================================================================
|
|
cmd_backup() {
|
|
local -a sites=() opts=()
|
|
local all="" dir="" label="" stop_site=""
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--site) sites+=("$2"); shift 2 ;;
|
|
--all) all=1; shift ;;
|
|
--dir) dir="$2"; shift 2 ;;
|
|
--label) label="$2"; shift 2 ;;
|
|
--no-rrds) opts+=(--no-rrds); shift ;;
|
|
--no-logs) opts+=(--no-logs); shift ;;
|
|
--stop) stop_site=1; shift ;;
|
|
*) die "Unbekannte Option fuer backup: $1" ;;
|
|
esac
|
|
done
|
|
require_cmk_running
|
|
dir="${dir:-$BACKUP_DIR}"
|
|
mkdir -p "$dir"
|
|
|
|
if [ -n "$all" ]; then
|
|
mapfile -t sites < <(cmk_sites)
|
|
fi
|
|
[ ${#sites[@]} -gt 0 ] || die "Keine Site angegeben (--site SITE oder --all)."
|
|
|
|
local s
|
|
for s in "${sites[@]}"; do
|
|
cmk_site_exists "$s" || die "Site '$s' existiert im Container nicht."
|
|
backup_one_site "$s" "$dir" "$label" "$stop_site" "${opts[@]+"${opts[@]}"}"
|
|
done
|
|
}
|
|
|
|
backup_one_site() {
|
|
local site="$1" dir="$2" label="$3" stop_site="$4"; shift 4
|
|
local -a opts=("$@")
|
|
local ts version outfile tmp restarted=""
|
|
ts="$(date +%Y%m%d-%H%M%S)"
|
|
version="$(cmk_site_version "$site")"
|
|
outfile="$dir/cmkbackup_${site}_${version:-unknown}${label:+_$label}_${ts}.tar.gz"
|
|
|
|
if [ -n "$stop_site" ] && [ "$(cmk_site_state "$site")" = "0" ]; then
|
|
log "Stoppe Site '$site' fuer ein konsistentes Backup ..."
|
|
ct omd stop "$site" >/dev/null
|
|
restarted=1
|
|
fi
|
|
|
|
tmp="$(mktemp -d)"
|
|
mkdir -p "$tmp/$BUNDLE_DIRNAME"
|
|
|
|
log "Erzeuge omd-Backup der Site '$site' ${opts[*]+(${opts[*]})} ..."
|
|
if ! $RUNTIME exec "$CMK_CONTAINER_NAME" omd backup ${opts[@]+"${opts[@]}"} "$site" - \
|
|
>"$tmp/$BUNDLE_DIRNAME/site.tar.gz" 2>"$tmp/err.log" \
|
|
|| [ ! -s "$tmp/$BUNDLE_DIRNAME/site.tar.gz" ]; then
|
|
warn "Streaming-Backup nicht moeglich - weiche auf Zwischendatei im Container aus."
|
|
debug "$(cat "$tmp/err.log" 2>/dev/null)"
|
|
ct sh -c "rm -f /var/tmp/cmkbackup.tar.gz"
|
|
ct omd backup ${opts[@]+"${opts[@]}"} "$site" /var/tmp/cmkbackup.tar.gz \
|
|
|| { rm -rf "$tmp"; die "omd backup fehlgeschlagen."; }
|
|
$RUNTIME cp "$CMK_CONTAINER_NAME:/var/tmp/cmkbackup.tar.gz" "$tmp/$BUNDLE_DIRNAME/site.tar.gz"
|
|
ct sh -c "rm -f /var/tmp/cmkbackup.tar.gz"
|
|
fi
|
|
|
|
[ -n "$restarted" ] && { log "Starte Site '$site' wieder ..."; ct omd start "$site" >/dev/null; }
|
|
|
|
local sum size
|
|
sum="$(sha256sum "$tmp/$BUNDLE_DIRNAME/site.tar.gz" | awk '{print $1}')"
|
|
size="$(file_size "$tmp/$BUNDLE_DIRNAME/site.tar.gz")"
|
|
printf '%s site.tar.gz\n' "$sum" >"$tmp/$BUNDLE_DIRNAME/site.tar.gz.sha256"
|
|
|
|
cat >"$tmp/$BUNDLE_DIRNAME/MANIFEST" <<EOF
|
|
BUNDLE_VERSION=1
|
|
BUNDLE_TYPE=backup
|
|
SITE=$site
|
|
CMK_VERSION=$version
|
|
SOURCE_KIND=container
|
|
SOURCE_HOST=$(hostname -f 2>/dev/null || hostname)
|
|
SOURCE_IP=$(primary_ip)
|
|
SOURCE_OS=$(. /etc/os-release 2>/dev/null && echo "$PRETTY_NAME" || echo unbekannt)
|
|
CREATED=$(date -Is)
|
|
CREATED_BY=cmk-manage.sh
|
|
ARCHIVE=site.tar.gz
|
|
ARCHIVE_SHA256=$sum
|
|
ARCHIVE_SIZE=$size
|
|
OMD_BACKUP_OPTS=${opts[*]-}
|
|
LABEL=$label
|
|
AGENT_RECEIVER_PORT=8000
|
|
EOF
|
|
|
|
cat >"$tmp/$BUNDLE_DIRNAME/INFO.txt" <<EOF
|
|
Checkmk Backup-Bundle
|
|
=====================
|
|
Site : $site
|
|
Checkmk-Version : $version ($(edition_from_version "$version"))
|
|
Erstellt : $(date -Is)
|
|
Quelle : Container '$CMK_CONTAINER_NAME' auf $(hostname)
|
|
Nutzdaten : site.tar.gz ($(human_size "$size"))
|
|
|
|
Wiederherstellen:
|
|
./scripts/cmk-manage.sh restore --file <diese-datei> --reuse
|
|
EOF
|
|
|
|
log "Verpacke Bundle ..."
|
|
tar -czf "$outfile" -C "$tmp" "$BUNDLE_DIRNAME"
|
|
rm -rf "$tmp"
|
|
ok "Backup erstellt: $outfile ($(human_size "$(file_size "$outfile")"))"
|
|
LAST_BACKUP_FILE="$outfile"
|
|
}
|
|
|
|
# =====================================================================
|
|
# Auflisten / Aufraeumen
|
|
# =====================================================================
|
|
list_backup_files() {
|
|
find "$BACKUP_DIR" -maxdepth 1 -type f \( -name '*.tar.gz' -o -name '*.tgz' \) -printf '%T@ %p\n' 2>/dev/null \
|
|
| sort -rn | cut -d' ' -f2-
|
|
}
|
|
|
|
cmd_list() {
|
|
local f n=0
|
|
printf '%-58s %10s %s\n' "DATEI" "GROESSE" "SITE / VERSION"
|
|
while IFS= read -r f; do
|
|
[ -n "$f" ] || continue
|
|
bundle_read "$f" 2>/dev/null || continue
|
|
printf '%-58s %10s %s / %s\n' "$(basename "$f")" \
|
|
"$(human_size "$(file_size "$f")")" "$B_SITE" "${B_CMK_VERSION:-?}"
|
|
n=$((n+1))
|
|
done < <(list_backup_files)
|
|
[ "$n" -eq 0 ] && echo "(keine Backups in $BACKUP_DIR)"
|
|
return 0
|
|
}
|
|
|
|
cmd_prune() {
|
|
local keep=5
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--keep) keep="$2"; shift 2 ;;
|
|
*) die "Unbekannte Option fuer prune: $1" ;;
|
|
esac
|
|
done
|
|
local -a files=(); mapfile -t files < <(list_backup_files)
|
|
if [ ${#files[@]} -le "$keep" ]; then
|
|
ok "Nichts zu loeschen (${#files[@]} Backups, behalte $keep)."
|
|
return 0
|
|
fi
|
|
local i
|
|
for ((i=keep; i<${#files[@]}; i++)); do
|
|
if confirm "Backup '$(basename "${files[$i]}")' loeschen?"; then
|
|
rm -f "${files[$i]}" && log "geloescht: $(basename "${files[$i]}")"
|
|
fi
|
|
done
|
|
ok "Aufraeumen beendet."
|
|
}
|
|
|
|
# =====================================================================
|
|
# Restore / Import (gemeinsame Implementierung)
|
|
# =====================================================================
|
|
do_restore() {
|
|
local file="$1" as_site="$2" reuse="$3" kill_opt="$4" nostart="$5" mode="$6"
|
|
|
|
[ -f "$file" ] || die "Datei nicht gefunden: $file"
|
|
require_cmk_running
|
|
bundle_read "$file" || die "'$file' ist kein Checkmk-Backup (weder Bundle noch omd-Archiv)."
|
|
|
|
local target="${as_site:-$B_SITE}"
|
|
|
|
echo
|
|
bundle_show "$file"
|
|
echo
|
|
printf '%sZiel-Site im Container : %s%s\n' "$C_BLD" "$target" "$C_RST"
|
|
|
|
# --- Pruefsumme -------------------------------------------------
|
|
if [ "$B_IS_BUNDLE" = 1 ] && [ -n "$B_ARCHIVE_SHA256" ]; then
|
|
log "Pruefe Pruefsumme ..."
|
|
local sum
|
|
sum="$(bundle_extract_payload "$file" | sha256sum | awk '{print $1}')"
|
|
[ "$sum" = "$B_ARCHIVE_SHA256" ] || die "Pruefsumme stimmt nicht - Bundle beschaedigt."
|
|
ok "Pruefsumme korrekt."
|
|
fi
|
|
|
|
# --- Versionspruefung -------------------------------------------
|
|
if [ -n "$B_CMK_VERSION" ]; then
|
|
local installed
|
|
installed="$(cmk_versions_installed)"
|
|
if ! 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' ' ')"
|
|
cat <<EOF
|
|
|
|
Loesung: in der .env die passende Version setzen und den Container neu erstellen,
|
|
danach importieren und erst anschliessend aktualisieren:
|
|
|
|
CMK_IMAGE_TAG=${B_CMK_VERSION%.*} # z.B. 2.3.0p23
|
|
./scripts/cmk-manage.sh up
|
|
./scripts/cmk-manage.sh $mode --file "$file"
|
|
|
|
("omd restore" kann eine Site nur wiederherstellen, wenn genau ihre
|
|
Version im Zielsystem vorhanden ist.)
|
|
EOF
|
|
die "Abbruch wegen Versionskonflikt."
|
|
fi
|
|
ok "Version $B_CMK_VERSION ist im Container vorhanden."
|
|
fi
|
|
|
|
# --- Editionspruefung -------------------------------------------
|
|
case "$B_CMK_VERSION" in
|
|
*.cee|*.cme|*.cce)
|
|
warn "Das Backup stammt aus einer $(edition_from_version "$B_CMK_VERSION").
|
|
Dafuer wird das passende Enterprise-/Cloud-Image benoetigt
|
|
(CMK_IMAGE_REPO=checkmk/check-mk-enterprise)." ;;
|
|
esac
|
|
|
|
# --- vorhandene Site --------------------------------------------
|
|
local -a rargs=()
|
|
if cmk_site_exists "$target"; then
|
|
if [ -z "$reuse" ]; then
|
|
die "Site '$target' existiert bereits. Mit --reuse ueberschreiben (Daten gehen verloren!)."
|
|
fi
|
|
warn "Die vorhandene Site '$target' wird UEBERSCHRIEBEN."
|
|
confirm "Wirklich fortfahren?" || die "Abgebrochen."
|
|
rargs+=(--reuse)
|
|
[ -n "$kill_opt" ] && rargs+=(--kill)
|
|
if [ "$(cmk_site_state "$target")" != "2" ]; then
|
|
log "Stoppe Site '$target' ..."
|
|
ct omd stop "$target" >/dev/null 2>&1 || true
|
|
fi
|
|
else
|
|
confirm "Site '$target' jetzt aus dem Backup wiederherstellen?" || die "Abgebrochen."
|
|
fi
|
|
|
|
if [ -n "$as_site" ] && [ "$as_site" != "$B_SITE" ]; then
|
|
warn "Die Site wird von '$B_SITE' nach '$as_site' umbenannt.
|
|
Registrierte Agents verweisen auf '$B_SITE' und muessen neu registriert werden!"
|
|
confirm "Trotzdem umbenennen?" || die "Abgebrochen."
|
|
rargs+=("$as_site")
|
|
fi
|
|
|
|
# --- Nutzdaten in den Container schieben ------------------------
|
|
local tmp; tmp="$(mktemp -d)"
|
|
log "Bereite Nutzdaten vor ..."
|
|
bundle_extract_payload "$file" >"$tmp/payload.tar.gz"
|
|
log "Kopiere Archiv in den Container ($(human_size "$(file_size "$tmp/payload.tar.gz")")) ..."
|
|
ct sh -c 'rm -f /var/tmp/cmkrestore.tar.gz'
|
|
$RUNTIME cp "$tmp/payload.tar.gz" "$CMK_CONTAINER_NAME:/var/tmp/cmkrestore.tar.gz"
|
|
rm -rf "$tmp"
|
|
|
|
log "Fuehre 'omd restore ${rargs[*]-} ' aus ..."
|
|
if ! ct omd restore ${rargs[@]+"${rargs[@]}"} /var/tmp/cmkrestore.tar.gz; then
|
|
ct sh -c 'rm -f /var/tmp/cmkrestore.tar.gz' || true
|
|
die "omd restore ist fehlgeschlagen."
|
|
fi
|
|
ct sh -c 'rm -f /var/tmp/cmkrestore.tar.gz' || true
|
|
ok "Site '$target' wurde wiederhergestellt."
|
|
|
|
# --- Nachbereitung ----------------------------------------------
|
|
# TMPFS im Container abschalten (Mount im Container nicht moeglich/noetig)
|
|
ct omd config "$target" set TMPFS off >/dev/null 2>&1 || true
|
|
|
|
if [ -z "$nostart" ]; then
|
|
log "Starte Site '$target' ..."
|
|
ct omd start "$target" || warn "Site konnte nicht vollstaendig gestartet werden - bitte 'omd status $target' pruefen."
|
|
fi
|
|
|
|
post_restore_hints "$target" "$mode"
|
|
}
|
|
|
|
post_restore_hints() {
|
|
local target="$1" mode="$2" ip; ip="$(primary_ip)"
|
|
cat <<EOF
|
|
|
|
${C_BLD}Naechste Schritte${C_RST}
|
|
1) Standard-Site im Container:
|
|
In der .env CMK_SITE_ID=$target setzen, sonst startet der Container
|
|
nach einem Reboot nur die urspruengliche Site.
|
|
(automatisch: $0 $mode --file ... --set-default-site)
|
|
2) Erreichbarkeit pruefen:
|
|
http://$ip:5000/$target/
|
|
3) Im NGINX Proxy Manager einen Proxy-Host anlegen:
|
|
Domain -> Forward to http://127.0.0.1:5000
|
|
4) Agents: solange Site-Name (${target}) und IP-Adresse gleich bleiben und
|
|
Port 8000 (Agent-Receiver) offen ist, muessen die Agents NICHT neu
|
|
registriert werden - die Site-Zertifikate sind im Backup enthalten.
|
|
Pruefen: $0 omd su $target -> cmk -O ; danach im GUI die
|
|
Host-Status/Agent-Verbindungen kontrollieren.
|
|
|
|
EOF
|
|
}
|
|
|
|
cmd_restore() {
|
|
local file="" as_site="" reuse="" kill_opt="" nostart=""
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--file) file="$2"; shift 2 ;;
|
|
--as-site) as_site="$2"; shift 2 ;;
|
|
--reuse) reuse=1; shift ;;
|
|
--kill) kill_opt=1; shift ;;
|
|
--no-start) nostart=1; shift ;;
|
|
*) die "Unbekannte Option fuer restore: $1" ;;
|
|
esac
|
|
done
|
|
[ -n "$file" ] || die "--file fehlt."
|
|
do_restore "$file" "$as_site" "$reuse" "$kill_opt" "$nostart" "restore"
|
|
}
|
|
|
|
cmd_import() {
|
|
local file="" reuse="" kill_opt="" nostart="" setdefault=""
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--file) file="$2"; shift 2 ;;
|
|
--reuse) reuse=1; shift ;;
|
|
--kill) kill_opt=1; shift ;;
|
|
--no-start) nostart=1; shift ;;
|
|
--set-default-site) setdefault=1; shift ;;
|
|
*) die "Unbekannte Option fuer import: $1" ;;
|
|
esac
|
|
done
|
|
[ -n "$file" ] || die "--file fehlt."
|
|
|
|
bundle_read "$file" || die "'$file' ist kein gueltiges Migrations-Bundle."
|
|
if [ "$B_IS_BUNDLE" = 1 ] && [ "$B_BUNDLE_TYPE" = "migrate" ]; then
|
|
log "Migrations-Bundle erkannt (Quelle: ${B_SOURCE_HOST:-?} / ${B_SOURCE_IP:-?})."
|
|
local myip; myip="$(primary_ip)"
|
|
if [ -n "$B_SOURCE_IP" ] && [ "$B_SOURCE_IP" != "$myip" ]; then
|
|
warn "Die IP dieses Hosts ($myip) weicht von der Quell-IP ($B_SOURCE_IP) ab.
|
|
Damit registrierte Agents ohne Neuregistrierung weiterarbeiten, muss dieser
|
|
Host die IP $B_SOURCE_IP uebernehmen (bzw. der DNS-Name darauf zeigen)."
|
|
confirm "Trotzdem importieren?" || die "Abgebrochen."
|
|
fi
|
|
fi
|
|
|
|
do_restore "$file" "" "$reuse" "$kill_opt" "$nostart" "import"
|
|
|
|
if [ -n "$setdefault" ]; then
|
|
env_set CMK_SITE_ID "$B_SITE"
|
|
ok "CMK_SITE_ID=$B_SITE in der .env gesetzt."
|
|
warn "Damit die Aenderung wirkt, den Container neu erstellen: $0 up"
|
|
fi
|
|
}
|
|
|
|
# =====================================================================
|
|
# Selbstsigniertes Zertifikat fuer den NGINX Proxy Manager
|
|
# =====================================================================
|
|
cmd_cert() {
|
|
local domain="${CERT_DOMAIN:-checkmk.example.local}" days="${CERT_DAYS:-3650}"
|
|
local -a alts=()
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--domain) domain="$2"; shift 2 ;;
|
|
--alt) alts+=("$2"); shift 2 ;;
|
|
--days) days="$2"; shift 2 ;;
|
|
*) die "Unbekannte Option fuer cert: $1" ;;
|
|
esac
|
|
done
|
|
command -v openssl >/dev/null 2>&1 || die "openssl ist nicht installiert."
|
|
|
|
local outdir="$PROJECT_DIR/data/npm/custom-certs/$domain"
|
|
mkdir -p "$outdir"
|
|
|
|
local san="DNS:$domain"
|
|
local a
|
|
for a in ${alts[@]+"${alts[@]}"}; do
|
|
case "$a" in
|
|
[0-9]*.[0-9]*.[0-9]*.[0-9]*) san="$san,IP:$a" ;;
|
|
*) san="$san,DNS:$a" ;;
|
|
esac
|
|
done
|
|
local myip; myip="$(primary_ip)"
|
|
[ -n "$myip" ] && san="$san,IP:$myip"
|
|
|
|
log "Erzeuge selbstsigniertes Zertifikat fuer '$domain' ($days Tage) ..."
|
|
openssl req -x509 -nodes -newkey rsa:4096 -sha256 -days "$days" \
|
|
-keyout "$outdir/privkey.pem" -out "$outdir/fullchain.pem" \
|
|
-subj "/C=${CERT_COUNTRY:-DE}/O=${CERT_ORG:-Selfsigned}/CN=$domain" \
|
|
-addext "subjectAltName=$san" \
|
|
-addext "basicConstraints=critical,CA:FALSE" \
|
|
-addext "keyUsage=critical,digitalSignature,keyEncipherment" \
|
|
-addext "extendedKeyUsage=serverAuth" 2>/dev/null \
|
|
|| die "Zertifikatserstellung fehlgeschlagen."
|
|
chmod 600 "$outdir/privkey.pem"
|
|
|
|
ok "Zertifikat erstellt:"
|
|
printf ' Schluessel : %s\n' "$outdir/privkey.pem"
|
|
printf ' Zertifikat : %s\n' "$outdir/fullchain.pem"
|
|
printf ' SAN : %s\n\n' "$san"
|
|
cat <<EOF
|
|
Einbinden im NGINX Proxy Manager:
|
|
1) http://$(primary_ip):81 -> SSL Certificates -> Add SSL Certificate -> Custom
|
|
2) Name z.B. "$domain"
|
|
Certificate Key : privkey.pem
|
|
Certificate : fullchain.pem
|
|
3) Im Proxy-Host unter "SSL" dieses Zertifikat auswaehlen,
|
|
"Force SSL" und "HTTP/2 Support" aktivieren.
|
|
EOF
|
|
}
|
|
|
|
# =====================================================================
|
|
# ncurses-Oberflaeche
|
|
# =====================================================================
|
|
gui_pick_site() { # -> Site auf stdout
|
|
local -a items=() s
|
|
while IFS= read -r s; do
|
|
[ -n "$s" ] || continue
|
|
items+=("$s" "$(cmk_site_version "$s") / $(cmk_site_state_text "$s")")
|
|
done < <(cmk_sites)
|
|
[ ${#items[@]} -gt 0 ] || { ui_msg "Sites" "Im Container ist keine Site vorhanden."; return 1; }
|
|
ui_menu "Site waehlen" "Vorhandene Sites im Container:" "${items[@]}"
|
|
}
|
|
|
|
gui_pick_backup() { # -> Datei auf stdout
|
|
local -a items=() f
|
|
while IFS= read -r f; do
|
|
[ -n "$f" ] || continue
|
|
bundle_read "$f" 2>/dev/null || continue
|
|
items+=("$f" "$B_SITE ${B_CMK_VERSION:-?} $(human_size "$(file_size "$f")")")
|
|
done < <(list_backup_files)
|
|
if [ ${#items[@]} -eq 0 ]; then
|
|
ui_msg "Backups" "In $BACKUP_DIR wurde kein Backup gefunden.\n\nAlternativ kann im naechsten Schritt frei im Dateisystem gesucht werden."
|
|
ui_pick_file "$PROJECT_DIR" '*.tar.gz'
|
|
return
|
|
fi
|
|
items+=("__browse__" "... anderes Verzeichnis durchsuchen ...")
|
|
local sel
|
|
sel="$(ui_menu "Backup waehlen" "Backups in $BACKUP_DIR:" "${items[@]}")" || return 1
|
|
if [ "$sel" = "__browse__" ]; then
|
|
ui_pick_file "$PROJECT_DIR" '*.tar.gz'
|
|
else
|
|
printf '%s\n' "$sel"
|
|
fi
|
|
}
|
|
|
|
gui_status() {
|
|
local f; f="$(mktemp)"
|
|
NO_COLOR=1 cmd_status >"$f" 2>&1 || true
|
|
ui_text "Status" "$f"
|
|
rm -f "$f"
|
|
}
|
|
|
|
gui_stack_menu() {
|
|
while :; do
|
|
local sel
|
|
sel="$(ui_menu "Stack steuern" "Container-Runtime: $RUNTIME" \
|
|
up "Stack starten (compose up -d)" \
|
|
restart "Stack neu starten" \
|
|
down "Stack stoppen und entfernen" \
|
|
pull "Images aktualisieren" \
|
|
logs "Letzte 200 Logzeilen ansehen" \
|
|
back "zurueck")" || return 0
|
|
case "$sel" in
|
|
up) ui_run "Stack starten" bash -c "cd '$PROJECT_DIR' && '$SELF' up" ;;
|
|
restart) ui_run "Neu starten" bash -c "cd '$PROJECT_DIR' && '$SELF' restart" ;;
|
|
down) ui_yesno "Stack stoppen" "Container wirklich stoppen und entfernen?\n(Die Daten unter ./data bleiben erhalten.)" \
|
|
&& ui_run "Stack stoppen" bash -c "cd '$PROJECT_DIR' && '$SELF' down" ;;
|
|
pull) ui_run "Images laden" bash -c "cd '$PROJECT_DIR' && '$SELF' pull" ;;
|
|
logs) local lf; lf="$(mktemp)"; compose logs --tail=200 >"$lf" 2>&1 || true
|
|
ui_text "Logs (letzte 200 Zeilen)" "$lf"; rm -f "$lf" ;;
|
|
back) return 0 ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
gui_backup() {
|
|
require_cmk_running
|
|
local -a items=() s
|
|
while IFS= read -r s; do
|
|
[ -n "$s" ] || continue
|
|
items+=("$s" "$(cmk_site_version "$s")" off)
|
|
done < <(cmk_sites)
|
|
[ ${#items[@]} -gt 0 ] || { ui_msg "Backup" "Keine Sites vorhanden."; return; }
|
|
|
|
local chosen
|
|
chosen="$(ui_checklist "Backup" "Zu sichernde Site(s) mit LEERTASTE markieren:" "${items[@]}")" || return
|
|
[ -n "$chosen" ] || { ui_msg "Backup" "Keine Site ausgewaehlt."; return; }
|
|
|
|
local optsel
|
|
optsel="$(ui_checklist "Backup-Optionen" "Optionen waehlen:" \
|
|
no-rrds "Performance-Daten (RRD) auslassen - kleineres Archiv" off \
|
|
no-logs "Logdateien auslassen" off \
|
|
stop "Site waehrend des Backups stoppen (konsistenter)" off)" || return
|
|
|
|
local label
|
|
label="$(ui_input "Kennzeichnung" "Optionaler Text fuer den Dateinamen (leer = keiner):" "")" || label=""
|
|
label="$(printf '%s' "$label" | tr -cd 'A-Za-z0-9._-')"
|
|
|
|
local -a args=(backup --dir "$BACKUP_DIR")
|
|
[ -n "$label" ] && args+=(--label "$label")
|
|
case "$optsel" in *no-rrds*) args+=(--no-rrds);; esac
|
|
case "$optsel" in *no-logs*) args+=(--no-logs);; esac
|
|
case "$optsel" in *stop*) args+=(--stop);; esac
|
|
local sitename
|
|
for sitename in $(printf '%s' "$chosen" | tr -d '"'); do
|
|
args+=(--site "$sitename")
|
|
done
|
|
|
|
ui_run "Backup laeuft" bash -c "cd '$PROJECT_DIR' && '$SELF' -y ${args[*]}"
|
|
}
|
|
|
|
gui_restore() {
|
|
require_cmk_running
|
|
local file; file="$(gui_pick_backup)" || return
|
|
[ -n "$file" ] || return
|
|
|
|
local f; f="$(mktemp)"
|
|
bundle_show "$file" >"$f" 2>&1 || true
|
|
ui_text "Backup-Informationen" "$f"; rm -f "$f"
|
|
|
|
bundle_read "$file" || { ui_msg "Fehler" "Diese Datei ist kein Checkmk-Backup."; return; }
|
|
local reuse=""
|
|
if cmk_site_exists "$B_SITE"; then
|
|
ui_yesno "Site existiert" "Die Site '$B_SITE' ist bereits vorhanden.\n\nSoll sie UEBERSCHRIEBEN werden?\nAlle aktuellen Daten dieser Site gehen verloren!" || return
|
|
reuse="--reuse --kill"
|
|
fi
|
|
ui_yesno "Restore starten" "Site '$B_SITE' aus\n$(basename "$file")\nwiederherstellen?" || return
|
|
ui_run "Restore laeuft" bash -c "cd '$PROJECT_DIR' && '$SELF' -y restore --file '$file' $reuse"
|
|
}
|
|
|
|
gui_import() {
|
|
require_cmk_running
|
|
ui_msg "Site importieren" \
|
|
"Import einer Site von einer Direktinstallation (Bare-Metal/VM).
|
|
|
|
Voraussetzung: auf dem Quellserver wurde mit 'migrate_creator.sh'
|
|
ein Migrations-Bundle (.tar.gz) erzeugt und hierher kopiert.
|
|
|
|
Wichtig fuer die Agents:
|
|
- Site-Name bleibt unveraendert
|
|
- dieser Host uebernimmt die IP/den DNS-Namen des Quellservers
|
|
- Port 8000 (Agent-Receiver) ist erreichbar
|
|
Dann muessen die Agents NICHT neu eingerichtet werden."
|
|
|
|
local file; file="$(gui_pick_backup)" || return
|
|
[ -n "$file" ] || return
|
|
|
|
local f; f="$(mktemp)"
|
|
bundle_show "$file" >"$f" 2>&1 || true
|
|
ui_text "Bundle-Informationen" "$f"; rm -f "$f"
|
|
|
|
bundle_read "$file" || { ui_msg "Fehler" "Diese Datei ist kein Migrations-Bundle."; return; }
|
|
local reuse=""
|
|
if cmk_site_exists "$B_SITE"; then
|
|
ui_yesno "Site existiert" "Die Site '$B_SITE' existiert bereits im Container.\n\nUEBERSCHREIBEN?" || return
|
|
reuse="--reuse --kill"
|
|
fi
|
|
local setdef=""
|
|
ui_yesno "Standard-Site" "Soll CMK_SITE_ID in der .env auf '$B_SITE' gesetzt werden?\n\n(Empfohlen - sonst startet der Container nach einem Reboot\ndie importierte Site nicht automatisch.)" \
|
|
&& setdef="--set-default-site"
|
|
|
|
ui_run "Import laeuft" bash -c "cd '$PROJECT_DIR' && '$SELF' -y import --file '$file' $reuse $setdef"
|
|
}
|
|
|
|
gui_backups_menu() {
|
|
while :; do
|
|
local sel
|
|
sel="$(ui_menu "Backups verwalten" "Verzeichnis: $BACKUP_DIR" \
|
|
list "Backups auflisten" \
|
|
info "Details eines Backups anzeigen" \
|
|
verify "Backup pruefen (Struktur + Pruefsumme)" \
|
|
del "Backup loeschen" \
|
|
back "zurueck")" || return 0
|
|
case "$sel" in
|
|
list) local f; f="$(mktemp)"; NO_COLOR=1 cmd_list >"$f" 2>&1 || true
|
|
ui_text "Backups" "$f"; rm -f "$f" ;;
|
|
info) local b; b="$(gui_pick_backup)" || continue; [ -n "$b" ] || continue
|
|
local f2; f2="$(mktemp)"; bundle_show "$b" >"$f2" 2>&1 || true
|
|
ui_text "Details" "$f2"; rm -f "$f2" ;;
|
|
verify) local b2; b2="$(gui_pick_backup)" || continue; [ -n "$b2" ] || continue
|
|
ui_run "Pruefe Bundle" bash -c "cd '$PROJECT_DIR' && '$SELF' verify --file '$b2'" ;;
|
|
del) local b3; b3="$(gui_pick_backup)" || continue; [ -n "$b3" ] || continue
|
|
ui_yesno "Loeschen" "Datei wirklich loeschen?\n\n$b3" && rm -f "$b3" \
|
|
&& ui_msg "Geloescht" "Die Datei wurde entfernt." ;;
|
|
back) return 0 ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
gui_sites_menu() {
|
|
require_cmk_running
|
|
while :; do
|
|
local sel
|
|
sel="$(ui_menu "Sites" "Sites im Container '$CMK_CONTAINER_NAME'" \
|
|
list "Sites anzeigen" \
|
|
start "Site starten" \
|
|
stop "Site stoppen" \
|
|
all "alle Sites starten" \
|
|
back "zurueck")" || return 0
|
|
case "$sel" in
|
|
list) local f; f="$(mktemp)"; cmd_sites >"$f" 2>&1 || true; ui_text "Sites" "$f"; rm -f "$f" ;;
|
|
start) local s; s="$(gui_pick_site)" || continue; [ -n "$s" ] || continue
|
|
ui_run "Site starten" bash -c "cd '$PROJECT_DIR' && '$SELF' site-start '$s'" ;;
|
|
stop) local s2; s2="$(gui_pick_site)" || continue; [ -n "$s2" ] || continue
|
|
ui_run "Site stoppen" bash -c "cd '$PROJECT_DIR' && '$SELF' site-stop '$s2'" ;;
|
|
all) ui_run "Alle Sites starten" bash -c "cd '$PROJECT_DIR' && '$SELF' start-all-sites" ;;
|
|
back) return 0 ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
gui_cert() {
|
|
local domain alt days
|
|
domain="$(ui_input "Zertifikat" "FQDN / Common Name:" "${CERT_DOMAIN:-checkmk.example.local}")" || return
|
|
[ -n "$domain" ] || return
|
|
alt="$(ui_input "Zertifikat" "Weitere Namen/IPs (durch Leerzeichen getrennt, optional):" "$(primary_ip)")" || alt=""
|
|
days="$(ui_input "Zertifikat" "Gueltigkeit in Tagen:" "${CERT_DAYS:-3650}")" || days=3650
|
|
local -a a=(); local x
|
|
for x in $alt; do a+=(--alt "$x"); done
|
|
ui_run "Zertifikat erzeugen" bash -c "cd '$PROJECT_DIR' && '$SELF' cert --domain '$domain' --days '$days' ${a[*]+${a[*]}}"
|
|
}
|
|
|
|
gui_env() {
|
|
local f="${ENV_FILE:-$PROJECT_DIR/.env}"
|
|
[ -f "$f" ] || { ui_msg ".env" "Keine .env vorhanden."; return; }
|
|
ui_text "Konfiguration ($f)" "$f"
|
|
if ui_yesno "Bearbeiten" "Die .env jetzt im Editor oeffnen?"; then
|
|
"${EDITOR:-nano}" "$f"
|
|
load_env "$f"
|
|
fi
|
|
}
|
|
|
|
gui_main() {
|
|
ui_require
|
|
while :; do
|
|
local sel
|
|
sel="$(ui_menu "Checkmk Stack Manager" \
|
|
"Projekt : $PROJECT_DIR
|
|
Runtime : $RUNTIME Standard-Site: $CMK_SITE_ID
|
|
Backups : $BACKUP_DIR" \
|
|
status "Status von Containern und Sites" \
|
|
stack "Stack steuern (Start/Stop/Logs/Update)" \
|
|
backup "Backup erstellen" \
|
|
restore "Backup wiederherstellen" \
|
|
import "Site von Direktinstallation importieren" \
|
|
manage "Backups verwalten (Liste/Details/Loeschen)" \
|
|
sites "Sites im Container verwalten" \
|
|
cert "Selbstsigniertes Zertifikat erzeugen" \
|
|
env "Konfiguration (.env) ansehen/bearbeiten" \
|
|
shell "Root-Shell im Checkmk-Container" \
|
|
quit "Beenden")" || break
|
|
case "$sel" in
|
|
status) gui_status ;;
|
|
stack) gui_stack_menu ;;
|
|
backup) gui_backup ;;
|
|
restore) gui_restore ;;
|
|
import) gui_import ;;
|
|
manage) gui_backups_menu ;;
|
|
sites) gui_sites_menu ;;
|
|
cert) gui_cert ;;
|
|
env) gui_env ;;
|
|
shell) clear; cmd_shell || true ;;
|
|
quit) break ;;
|
|
esac
|
|
done
|
|
clear
|
|
ok "Beendet."
|
|
}
|
|
|
|
# =====================================================================
|
|
# Einstiegspunkt
|
|
# =====================================================================
|
|
main() {
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--env-file) ENVFILE_OPT="$2"; shift 2 ;;
|
|
-y|--yes) ASSUME_YES=1; shift ;;
|
|
-v|--verbose) VERBOSE=1; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) break ;;
|
|
esac
|
|
done
|
|
|
|
load_env "${ENVFILE_OPT:-$PROJECT_DIR/.env}"
|
|
detect_runtime
|
|
UI_BACKTITLE="Checkmk Stack Manager - Runtime: $RUNTIME"
|
|
|
|
local cmd="${1:-gui}"; [ $# -gt 0 ] && shift || true
|
|
case "$cmd" in
|
|
gui|menu) gui_main ;;
|
|
up|start) cmd_up ;;
|
|
down|stop) cmd_down ;;
|
|
restart) cmd_restart ;;
|
|
pull) cmd_pull ;;
|
|
status) cmd_status ;;
|
|
logs) cmd_logs "$@" ;;
|
|
shell) cmd_shell ;;
|
|
omd) cmd_omd "$@" ;;
|
|
sites) cmd_sites ;;
|
|
site-start) cmd_site_start "$@" ;;
|
|
site-stop) cmd_site_stop "$@" ;;
|
|
start-all-sites) cmd_start_all_sites ;;
|
|
backup) cmd_backup "$@" ;;
|
|
list) cmd_list ;;
|
|
prune) cmd_prune "$@" ;;
|
|
verify) local vf=""; [ "${1:-}" = "--file" ] && vf="$2"; [ -n "$vf" ] || vf="${1:-}"
|
|
[ -n "$vf" ] || die "--file fehlt."; bundle_verify "$vf" ;;
|
|
restore) cmd_restore "$@" ;;
|
|
import) cmd_import "$@" ;;
|
|
cert) cmd_cert "$@" ;;
|
|
help|-h|--help) usage ;;
|
|
*) err "Unbekanntes Kommando: $cmd"; echo; usage; exit 1 ;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|