first commit
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
#!/usr/bin/env bash
|
||||
# =====================================================================
|
||||
# common.sh - gemeinsame Funktionen fuer cmk-manage.sh
|
||||
# Wird per "source" eingebunden, nicht direkt ausgefuehrt.
|
||||
# =====================================================================
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Ausgabe / Logging
|
||||
# ---------------------------------------------------------------------
|
||||
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
|
||||
C_RED=$'\033[31m'; C_GRN=$'\033[32m'; C_YEL=$'\033[33m'
|
||||
C_BLU=$'\033[34m'; C_BLD=$'\033[1m'; C_RST=$'\033[0m'
|
||||
else
|
||||
C_RED=; C_GRN=; C_YEL=; C_BLU=; C_BLD=; C_RST=
|
||||
fi
|
||||
|
||||
log() { printf '%s[ %s ]%s %s\n' "$C_BLU" "INFO" "$C_RST" "$*"; }
|
||||
ok() { printf '%s[ OK ]%s %s\n' "$C_GRN" "$C_RST" "$*"; }
|
||||
warn() { printf '%s[ WARN ]%s %s\n' "$C_YEL" "$C_RST" "$*" >&2; }
|
||||
err() { printf '%s[FEHLER]%s %s\n' "$C_RED" "$C_RST" "$*" >&2; }
|
||||
die() { err "$*"; exit 1; }
|
||||
debug() { [ -n "${VERBOSE:-}" ] && printf ' > %s\n' "$*" >&2 || true; }
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# .env laden
|
||||
# ---------------------------------------------------------------------
|
||||
load_env() {
|
||||
local envfile="${1:-$PROJECT_DIR/.env}"
|
||||
if [ -f "$envfile" ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
. "$envfile"
|
||||
set +a
|
||||
ENV_FILE="$envfile"
|
||||
else
|
||||
warn "Keine .env gefunden ($envfile) - es gelten die Standardwerte."
|
||||
ENV_FILE=""
|
||||
fi
|
||||
# Defaults
|
||||
CMK_CONTAINER_NAME="${CMK_CONTAINER_NAME:-checkmk}"
|
||||
NPM_CONTAINER_NAME="${NPM_CONTAINER_NAME:-nginx-proxy-manager}"
|
||||
CMK_SITE_ID="${CMK_SITE_ID:-cmk}"
|
||||
BACKUP_DIR="${BACKUP_DIR:-$PROJECT_DIR/backups}"
|
||||
case "$BACKUP_DIR" in
|
||||
/*) : ;;
|
||||
*) BACKUP_DIR="$PROJECT_DIR/${BACKUP_DIR#./}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# .env-Wert dauerhaft setzen
|
||||
env_set() {
|
||||
local key="$1" val="$2" f="${ENV_FILE:-$PROJECT_DIR/.env}"
|
||||
[ -f "$f" ] || die "Keine .env vorhanden - kann '$key' nicht setzen."
|
||||
if grep -qE "^[#[:space:]]*${key}=" "$f"; then
|
||||
sed -i -E "s|^[#[:space:]]*${key}=.*|${key}=${val}|" "$f"
|
||||
else
|
||||
printf '%s=%s\n' "$key" "$val" >>"$f"
|
||||
fi
|
||||
export "$key=$val"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Container-Runtime erkennen (docker / podman)
|
||||
# ---------------------------------------------------------------------
|
||||
detect_runtime() {
|
||||
if [ -n "${CMK_RUNTIME:-}" ]; then
|
||||
command -v "$CMK_RUNTIME" >/dev/null 2>&1 \
|
||||
|| die "CMK_RUNTIME='$CMK_RUNTIME' ist nicht installiert."
|
||||
RUNTIME="$CMK_RUNTIME"
|
||||
elif command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
|
||||
RUNTIME=docker
|
||||
elif command -v podman >/dev/null 2>&1; then
|
||||
RUNTIME=podman
|
||||
elif command -v docker >/dev/null 2>&1; then
|
||||
RUNTIME=docker # vorhanden, aber Daemon evtl. gestoppt
|
||||
else
|
||||
die "Weder docker noch podman gefunden. Bitte zuerst ./install.sh ausfuehren."
|
||||
fi
|
||||
debug "Runtime: $RUNTIME"
|
||||
}
|
||||
|
||||
# Compose-Kommando ermitteln (als Array COMPOSE_CMD)
|
||||
detect_compose() {
|
||||
COMPOSE_CMD=()
|
||||
if [ "$RUNTIME" = docker ]; then
|
||||
if docker compose version >/dev/null 2>&1; then
|
||||
COMPOSE_CMD=(docker compose)
|
||||
elif command -v docker-compose >/dev/null 2>&1; then
|
||||
COMPOSE_CMD=(docker-compose)
|
||||
fi
|
||||
else
|
||||
if command -v podman-compose >/dev/null 2>&1; then
|
||||
COMPOSE_CMD=(podman-compose)
|
||||
elif podman compose version >/dev/null 2>&1; then
|
||||
COMPOSE_CMD=(podman compose)
|
||||
fi
|
||||
fi
|
||||
[ ${#COMPOSE_CMD[@]} -gt 0 ] || die "Kein Compose-Kommando gefunden (docker compose / podman-compose)."
|
||||
debug "Compose: ${COMPOSE_CMD[*]}"
|
||||
}
|
||||
|
||||
compose() {
|
||||
detect_compose
|
||||
( cd "$PROJECT_DIR" && "${COMPOSE_CMD[@]}" "$@" )
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Container-Helfer
|
||||
# ---------------------------------------------------------------------
|
||||
container_exists() { $RUNTIME container inspect "$1" >/dev/null 2>&1; }
|
||||
container_running() { [ "$($RUNTIME container inspect -f '{{.State.Running}}' "$1" 2>/dev/null)" = "true" ]; }
|
||||
|
||||
require_cmk_running() {
|
||||
container_exists "$CMK_CONTAINER_NAME" \
|
||||
|| die "Container '$CMK_CONTAINER_NAME' existiert nicht. Zuerst: $0 up"
|
||||
container_running "$CMK_CONTAINER_NAME" \
|
||||
|| die "Container '$CMK_CONTAINER_NAME' laeuft nicht. Zuerst: $0 up"
|
||||
}
|
||||
|
||||
# Kommando im Checkmk-Container als root ausfuehren
|
||||
ct() { $RUNTIME exec "$CMK_CONTAINER_NAME" "$@"; }
|
||||
# ... mit stdin
|
||||
cti() { $RUNTIME exec -i "$CMK_CONTAINER_NAME" "$@"; }
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# OMD-Helfer (im Container)
|
||||
# ---------------------------------------------------------------------
|
||||
cmk_sites() {
|
||||
ct sh -c 'ls -1 /omd/sites 2>/dev/null' | sed '/^$/d' || true
|
||||
}
|
||||
|
||||
cmk_site_exists() {
|
||||
cmk_sites | grep -qxF "$1"
|
||||
}
|
||||
|
||||
cmk_site_version() {
|
||||
ct omd version -b "$1" 2>/dev/null | tr -d '\r' || true
|
||||
}
|
||||
|
||||
# 0 = laeuft komplett, 1 = teilweise, 2 = gestoppt
|
||||
cmk_site_state() {
|
||||
local rc=0
|
||||
ct omd status --bare "$1" >/dev/null 2>&1 || rc=$?
|
||||
echo "$rc"
|
||||
}
|
||||
|
||||
cmk_site_state_text() {
|
||||
case "$(cmk_site_state "$1")" in
|
||||
0) echo "laeuft" ;;
|
||||
1) echo "teilweise" ;;
|
||||
*) echo "gestoppt" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
cmk_versions_installed() {
|
||||
ct omd versions -b 2>/dev/null | tr -d '\r' || ct sh -c 'ls -1 /omd/versions | grep -v "^default$"' 2>/dev/null || true
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Diverses
|
||||
# ---------------------------------------------------------------------
|
||||
human_size() {
|
||||
local b="${1:-0}"
|
||||
if [ "$b" -ge 1073741824 ] 2>/dev/null; then awk -v b="$b" 'BEGIN{printf "%.1f GiB", b/1073741824}'
|
||||
elif [ "$b" -ge 1048576 ] 2>/dev/null; then awk -v b="$b" 'BEGIN{printf "%.1f MiB", b/1048576}'
|
||||
elif [ "$b" -ge 1024 ] 2>/dev/null; then awk -v b="$b" 'BEGIN{printf "%.1f KiB", b/1024}'
|
||||
else echo "${b} B"; fi
|
||||
}
|
||||
|
||||
file_size() { stat -c %s "$1" 2>/dev/null || echo 0; }
|
||||
|
||||
confirm() {
|
||||
[ -n "${ASSUME_YES:-}" ] && return 0
|
||||
local prompt="${1:-Fortfahren?} [j/N] " a
|
||||
read -r -p "$prompt" a </dev/tty || return 1
|
||||
case "$a" in [jJyY]*) return 0 ;; *) return 1 ;; esac
|
||||
}
|
||||
|
||||
primary_ip() {
|
||||
ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src"){print $(i+1);exit}}' \
|
||||
|| hostname -I 2>/dev/null | awk '{print $1}'
|
||||
}
|
||||
|
||||
# =====================================================================
|
||||
# TUI-Helfer (dialog bevorzugt, sonst whiptail) - ncurses wie im mc
|
||||
# =====================================================================
|
||||
UI_BACKTITLE="Checkmk Stack Manager - Container-Runtime: ${RUNTIME:-?}"
|
||||
|
||||
ui_init() {
|
||||
[ -n "${UI_BIN:-}" ] && return 0
|
||||
if command -v dialog >/dev/null 2>&1; then UI_BIN=dialog
|
||||
elif command -v whiptail >/dev/null 2>&1; then UI_BIN=whiptail
|
||||
else UI_BIN=""; fi
|
||||
UI_H="${UI_H:-22}"; UI_W="${UI_W:-78}"; UI_MH="${UI_MH:-13}"
|
||||
export DIALOGRC="${DIALOGRC:-}"
|
||||
}
|
||||
|
||||
ui_available() { ui_init; [ -n "$UI_BIN" ]; }
|
||||
|
||||
ui_require() {
|
||||
ui_available || die "Fuer die TUI wird 'dialog' oder 'whiptail' benoetigt.
|
||||
Debian/Ubuntu : apt-get install -y dialog
|
||||
RHEL/Rocky : dnf install -y dialog"
|
||||
UI_BACKTITLE="Checkmk Stack Manager - Runtime: $RUNTIME"
|
||||
}
|
||||
|
||||
ui_menu() { # title text tag item [tag item ...] -> gewaehlter tag auf stdout
|
||||
local title="$1" text="$2"; shift 2
|
||||
"$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$title" \
|
||||
--menu "$text" "$UI_H" "$UI_W" "$UI_MH" "$@" 3>&1 1>&2 2>&3
|
||||
}
|
||||
|
||||
ui_checklist() { # title text tag item status ...
|
||||
local title="$1" text="$2"; shift 2
|
||||
"$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$title" \
|
||||
--checklist "$text" "$UI_H" "$UI_W" "$UI_MH" "$@" 3>&1 1>&2 2>&3
|
||||
}
|
||||
|
||||
ui_radiolist() {
|
||||
local title="$1" text="$2"; shift 2
|
||||
"$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$title" \
|
||||
--radiolist "$text" "$UI_H" "$UI_W" "$UI_MH" "$@" 3>&1 1>&2 2>&3
|
||||
}
|
||||
|
||||
ui_input() { # title text default
|
||||
"$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" \
|
||||
--inputbox "$2" 10 "$UI_W" "${3:-}" 3>&1 1>&2 2>&3
|
||||
}
|
||||
|
||||
ui_password() {
|
||||
"$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" \
|
||||
--passwordbox "$2" 10 "$UI_W" 3>&1 1>&2 2>&3
|
||||
}
|
||||
|
||||
ui_msg() { # title text
|
||||
"$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" --msgbox "$2" 16 "$UI_W"
|
||||
}
|
||||
|
||||
ui_yesno() { # title text -> exit 0 = ja
|
||||
"$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" --yesno "$2" 14 "$UI_W"
|
||||
}
|
||||
|
||||
ui_text() { # title file
|
||||
"$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" --textbox "$2" "$UI_H" "$UI_W"
|
||||
}
|
||||
|
||||
ui_info() { # title text (ohne OK-Button)
|
||||
"$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" --infobox "$2" 8 "$UI_W"
|
||||
}
|
||||
|
||||
# Kommando ausfuehren, Ausgabe live in Datei, danach in Textbox anzeigen
|
||||
ui_run() { # title cmd...
|
||||
local title="$1"; shift
|
||||
local logf; logf="$(mktemp)"
|
||||
ui_info "$title" "Bitte warten ...\n\n$*"
|
||||
if "$@" >"$logf" 2>&1; then
|
||||
ui_text "$title - erfolgreich" "$logf"
|
||||
rm -f "$logf"; return 0
|
||||
else
|
||||
ui_text "$title - FEHLGESCHLAGEN" "$logf"
|
||||
rm -f "$logf"; return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Dateiauswahl im Midnight-Commander-Stil (funktioniert auch mit whiptail)
|
||||
# ---------------------------------------------------------------------
|
||||
ui_pick_file() { # startdir [glob] -> Dateipfad auf stdout
|
||||
local dir="${1:-$PWD}" glob="${2:-*}" sel
|
||||
dir="$(cd "$dir" 2>/dev/null && pwd || echo "$PWD")"
|
||||
while :; do
|
||||
local -a items=()
|
||||
items+=(".." "<Verzeichnis hoeher>")
|
||||
local d f
|
||||
while IFS= read -r d; do
|
||||
[ -n "$d" ] && items+=("$d/" "<DIR>")
|
||||
done < <(find "$dir" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' 2>/dev/null | sort)
|
||||
while IFS= read -r f; do
|
||||
[ -n "$f" ] || continue
|
||||
items+=("$f" "$(human_size "$(file_size "$dir/$f")")")
|
||||
done < <(find "$dir" -mindepth 1 -maxdepth 1 -type f -name "$glob" -printf '%f\n' 2>/dev/null | sort)
|
||||
|
||||
sel="$(ui_menu "Datei waehlen" "Verzeichnis: $dir\nFilter: $glob" "${items[@]}")" || return 1
|
||||
case "$sel" in
|
||||
"..") dir="$(dirname "$dir")" ;;
|
||||
*/) dir="$dir/${sel%/}" ;;
|
||||
*) printf '%s\n' "$dir/$sel"; return 0 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
Reference in New Issue
Block a user