Files
image-builder/scripts/image-builder.sh

885 lines
27 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
CONFIG_DIR="$ROOT_DIR/config"
GLOBAL_CONFIG="$CONFIG_DIR/global/config.json"
PROJECTS_DIR="$ROOT_DIR/projects"
PROJECT_CONFIG_DIR="$CONFIG_DIR/projects"
REGISTRY_CONFIG_DIR="$CONFIG_DIR/registries"
LOGS_DIR="$ROOT_DIR/logs"
ensure_dirs() {
mkdir -p "$CONFIG_DIR/global" "$CONFIG_DIR/projects" "$CONFIG_DIR/registries" "$ROOT_DIR/projects" "$LOGS_DIR"
if [[ ! -f "$GLOBAL_CONFIG" ]]; then
cat >"$GLOBAL_CONFIG" <<EOF
{
"editor": "nano"
}
EOF
fi
}
ensure_prereqs() {
local bins=("git" "jq" "whiptail")
for b in "${bins[@]}"; do
if ! command -v "$b" >/dev/null 2>&1; then
echo "[WARN] Benötigtes Programm fehlt: $b"
fi
done
}
load_global_config() {
if [[ -f "$GLOBAL_CONFIG" ]]; then
EDITOR_CMD=$(jq -r '.editor // "nano"' "$GLOBAL_CONFIG")
else
EDITOR_CMD="nano"
fi
}
ensure_dirs
load_global_config
# -------------------------
# Konfigurations-Menü
# -------------------------
config_menu() {
while true; do
local builder_icon
builder_icon=$(get_builder_status_icon)
choice=$(whiptail --title "Konfiguration" --menu "Bitte wählen:" 20 70 10 \
1 "Abhängigkeiten installieren (docker, git, jq, whiptail)" \
2 "Buildx-Builder einrichten | Status: $builder_icon" \
3 "Globalen Editor setzen" \
4 "Standard-Registry setzen" \
0 "Zurück" \
3>&1 1>&2 2>&3) || return
case $choice in
1) install_dependencies;;
2) install_docker_and_buildx;;
3) set_editor;;
4) set_default_registry ;;
0) return;;
esac
done
}
# BuildX-Builder Status Icon
get_builder_status_icon() {
if docker buildx ls 2>/dev/null | grep -q "multiarch-builder"; then
if docker buildx ls | grep "multiarch-builder" | grep -q "running"; then
echo "[OK]"
else
echo "[WARN]"
fi
else
echo "[ERR]"
fi
}
# BuildX-Builder-Status abrufen
get_builder_status() {
if docker buildx ls 2>/dev/null | grep -q "multiarch-builder"; then
if docker buildx ls | grep "multiarch-builder" | grep -q "running"; then
echo "[läuft]"
else
echo "[vorhanden, aber gestoppt]"
fi
else
echo "[nicht eingerichtet]"
fi
}
# Abhängigkeiten installieren
install_dependencies() {
whiptail --msgbox "Installation von Abhängigkeiten (Beispiel für Debian/Ubuntu). Bitte root-Rechte eingeben." 10 70
sudo apt update
sudo apt install -y docker.io git jq whiptail micro
}
# BuildX-Builder einrichten
install_docker_and_buildx() {
# Prüfen ob Docker installiert ist
if ! command -v docker >/dev/null 2>&1; then
whiptail --msgbox "Docker ist nicht installiert! Bitte zuerst über 'Abhängigkeiten installieren' einrichten." 10 70
return
fi
# Prüfen ob Buildx verfügbar ist
if ! docker buildx version >/dev/null 2>&1; then
whiptail --msgbox "Docker Buildx-Plugin fehlt! Installiere Buildx..." 10 70
mkdir -p ~/.docker/cli-plugins
BUILDX_URL="https://github.com/docker/buildx/releases/latest/download/buildx-$(uname -s)-$(uname -m)"
curl -sSL "$BUILDX_URL" -o ~/.docker/cli-plugins/docker-buildx
chmod +x ~/.docker/cli-plugins/docker-buildx
fi
# Prüfen, ob multiarch-builder existiert
if ! docker buildx ls | grep -q "multiarch-builder"; then
whiptail --msgbox "Richte Buildx-Builder 'multiarch-builder' ein..." 10 70
docker run --rm --privileged tonistiigi/binfmt --install all
docker buildx create --name multiarch-builder --use
docker buildx inspect --bootstrap >/dev/null 2>&1
fi
# Finalprüfung: existiert Builder jetzt wirklich?
if docker buildx ls | grep -q "multiarch-builder"; then
whiptail --msgbox "Buildx-Builder 'multiarch-builder' erfolgreich eingerichtet." 10 70
else
whiptail --msgbox "Fehler: Buildx-Builder konnte nicht eingerichtet werden!" 10 70
fi
}
# Standard Editor setzen
set_editor() {
# editor -> paketname
declare -A editor_pkg
editor_pkg=( ["nano"]="nano" ["vim"]="vim" ["micro"]="micro" ["nvim"]="neovim" )
local options=()
declare -A editor_status
# Prüfe, ob Editor installiert ist
for cmd in "${!editor_pkg[@]}"; do
if command -v "$cmd" >/dev/null 2>&1; then
editor_status[$cmd]="(installiert)"
else
editor_status[$cmd]="(nicht installiert)"
fi
options+=("$cmd" "${editor_status[$cmd]}")
done
while true; do
choice=$(whiptail --title "Editor wählen" --menu "Bitte Editor auswählen:" 20 70 10 "${options[@]}" 3>&1 1>&2 2>&3) || return
if command -v "$choice" >/dev/null 2>&1; then
jq --arg ed "$choice" '.editor = $ed' "$GLOBAL_CONFIG" >"$GLOBAL_CONFIG.tmp" && mv "$GLOBAL_CONFIG.tmp" "$GLOBAL_CONFIG"
whiptail --msgbox "Editor wurde auf '$choice' gesetzt." 10 60
return
else
install_choice=$(whiptail --title "Editor nicht installiert" \
--yesno "Der Editor '$choice' ist nicht installiert. Möchten Sie ihn jetzt installieren?" 10 60 3>&1 1>&2 2>&3)
if [[ $? -eq 0 ]]; then
whiptail --msgbox "Installation von ${editor_pkg[$choice]}..." 8 50
sudo apt update
sudo apt install -y "${editor_pkg[$choice]}"
if command -v "$choice" >/dev/null 2>&1; then
# Speziell für nano: Syntax-Highlighting installieren
if [[ "$choice" == "nano" ]]; then
NANO_DIR="$HOME/.nano"
NANORC="$HOME/.nanorc"
if [[ -d "$NANO_DIR/.git" ]]; then
git -C "$NANO_DIR" pull --quiet
else
git clone https://github.com/scopatz/nanorc.git "$NANO_DIR"
fi
if ! grep -q "include $NANO_DIR" "$NANORC" 2>/dev/null; then
{
echo "## nano syntax highlighting"
echo "include $NANO_DIR/*.nanorc"
} >> "$NANORC"
fi
fi
whiptail --msgbox "$choice erfolgreich installiert." 8 50
jq --arg ed "$choice" '.editor = $ed' "$GLOBAL_CONFIG" >"$GLOBAL_CONFIG.tmp" && mv "$GLOBAL_CONFIG.tmp" "$GLOBAL_CONFIG"
return
else
whiptail --msgbox "Fehler: $choice konnte nicht installiert werden." 8 50
fi
fi
fi
done
}
# Standard-Registry setzen
set_default_registry() {
# Alle verfügbaren Registries auslesen
local registries
registries=$(ls "$REGISTRY_CONFIG_DIR" 2>/dev/null)
[ -z "$registries" ] && { whiptail --msgbox "Keine Registries verfügbar. Bitte zuerst eine Registry erstellen." 10 60; return; }
# Menü-Liste vorbereiten
local menu_list=()
for r in $registries; do
menu_list+=("$r" "$r")
done
# Aktuelle Default-Registry auslesen
local current
current=$(jq -r '.default_registry // ""' "$GLOBAL_CONFIG")
# Auswahl per Whiptail
local choice
choice=$(whiptail --title "Standard-Registry wählen" \
--menu "Bitte Standard-Registry auswählen:" 20 70 10 \
"${menu_list[@]}" 3>&1 1>&2 2>&3) || return
# Speichern in global/config.json
jq --arg reg "$choice" '.default_registry = $reg' "$GLOBAL_CONFIG" >"$GLOBAL_CONFIG.tmp" && mv "$GLOBAL_CONFIG.tmp" "$GLOBAL_CONFIG"
whiptail --msgbox "Standard-Registry auf '$choice' gesetzt." 10 60
}
# Standard-Registry auslesen
get_default_registry() {
if [[ -f "$GLOBAL_CONFIG" ]]; then
jq -r '.default_registry // ""' "$GLOBAL_CONFIG"
else
echo ""
fi
}
# ===============================
# Projektverwaltung
# ===============================
# Hauptmenü Projektverwaltung
project_menu() {
while true; do
choice=$(whiptail --title "Projektverwaltung" --menu "Bitte wählen:" 20 70 10 \
1 "Projekt erstellen" \
2 "Projekt löschen" \
3 "Projekt bearbeiten" \
0 "Zurück" \
3>&1 1>&2 2>&3) || return
case $choice in
1) create_project ;;
2) delete_project ;;
3) edit_project ;;
0) return ;;
esac
done
}
# Neues Projekt anlegen
create_project() {
project_name=$(whiptail --inputbox "Projektname eingeben:" 10 60 3>&1 1>&2 2>&3) || return
[ -z "$project_name" ] && return
mkdir -p "$PROJECT_CONFIG_DIR/$project_name" "$PROJECTS_DIR/$project_name"
# Standardwerte setzen
default_registry=$(get_default_registry)
# Default Config-File
cat > "$PROJECT_CONFIG_DIR/$project_name/config-file" <<EOF
# Projektkonfiguration für $project_name
registry=$default_registry
image_name=$project_name
architectures=amd64
push=yes
version=1.0
latest=yes
auto_increment=no
git_repo=
EOF
# Dockerfile oder Git-Repo
if whiptail --yesno "Soll ein Git-Repo geklont werden?" 10 60; then
repo_url=$(whiptail --inputbox "Git-Repository-URL eingeben:" 10 60 3>&1 1>&2 2>&3) || return
if git clone "$repo_url" "$PROJECTS_DIR/$project_name"; then
sed -i "s|^git_repo=.*|git_repo=$repo_url|" "$PROJECT_CONFIG_DIR/$project_name/config-file"
else
whiptail --msgbox "Fehler beim Klonen des Git-Repos!" 10 60
fi
else
echo -e "FROM debian:bookworm-slim\nCMD echo 'Hello from $project_name'" > "$PROJECTS_DIR/$project_name/Dockerfile"
fi
whiptail --msgbox "Projekt $project_name wurde erstellt." 10 60
}
# Projekt löschen
delete_project() {
projects=$(ls "$PROJECT_CONFIG_DIR" 2>/dev/null)
[ -z "$projects" ] && { whiptail --msgbox "Keine Projekte vorhanden." 10 60; return; }
menu_list=()
for p in $projects; do
menu_list+=("$p" "")
done
project=$(whiptail --menu "Projekt zum Löschen auswählen:" 20 60 10 "${menu_list[@]}" 3>&1 1>&2 2>&3) || return
if whiptail --yesno "Projekt $project wirklich löschen?" 10 60; then
rm -rf "$PROJECT_CONFIG_DIR/$project" "$PROJECTS_DIR/$project"
whiptail --msgbox "Projekt $project wurde gelöscht." 10 60
fi
}
# Projekt bearbeiten
edit_project() {
projects=$(ls "$PROJECT_CONFIG_DIR" 2>/dev/null)
[ -z "$projects" ] && { whiptail --msgbox "Keine Projekte vorhanden." 10 60; return; }
# Projekte für Menü vorbereiten (1 Spalte)
menu_list=()
for p in $projects; do
menu_list+=("$p" "")
done
project=$(whiptail --menu "Projekt auswählen:" 20 60 10 "${menu_list[@]}" 3>&1 1>&2 2>&3) || return
local config_file="$PROJECT_CONFIG_DIR/$project/config-file"
local project_dir="$PROJECTS_DIR/$project"
while true; do
repo_url=$(grep "^git_repo=" "$config_file" | cut -d= -f2)
menu_items=(
1 "Registries auswählen"
2 "Architekturen auswählen"
3 "Push aktivieren/deaktivieren"
4 "Latest-Tag setzen/entfernen"
5 "Version/Subversion ändern"
6 "Automatische Subversion"
7 "Projektdateien bearbeiten"
9 "Image bauen"
)
[ -n "$repo_url" ] && menu_items+=("8" "Git Pull")
menu_items+=("0" "Zurück")
choice=$(whiptail --title "Projekt bearbeiten: $project" \
--menu "Bitte wählen:" 20 70 12 \
"${menu_items[@]}" \
3>&1 1>&2 2>&3) || return
case $choice in
1) edit_project_registries "$config_file" ;;
2) edit_project_architectures "$config_file" ;;
3) edit_project_push "$config_file" ;;
4) edit_project_latest "$config_file" ;;
5) change_project_setting "$config_file" "version" ;;
6) edit_project_auto_subversion "$config_file" ;;
7) edit_project_files "$project" ;;
8) [ -n "$repo_url" ] && (cd "$project_dir" && git pull || whiptail --msgbox "Git Pull fehlgeschlagen." 10 60) ;;
9) build_image "$project" ;;
0) return ;;
esac
done
}
# Registry für Projekt auswählen
edit_project_registries() {
local config_file=$1
# aktuelle registries im Projekt auslesen
local current=$(grep "^registry=" "$config_file" 2>/dev/null | cut -d= -f2 | tr ',' ' ')
# alle registries aus Registry-Verwaltung
local all_registries
all_registries=$(ls "$REGISTRY_CONFIG_DIR" 2>/dev/null)
[ -z "$all_registries" ] && { whiptail --msgbox "Keine Registries verfügbar. Bitte zuerst eine Registry erstellen." 10 60; return; }
# Default-Registry aus globaler Config
local default_registry
default_registry=$(get_default_registry)
# menu_list für whiptail vorbereiten
local menu_list=()
for r in $all_registries; do
if [[ " $current " =~ " $r " ]]; then
menu_list+=("$r" "$r" ON)
elif [[ -z "$current" && "$r" == "$default_registry" ]]; then
# Projekt hat noch keine registries, Default wird ON
menu_list+=("$r" "$r" ON)
else
menu_list+=("$r" "$r" OFF)
fi
done
# whiptail checklist
local selected
selected=$(whiptail --title "Registries auswählen" --checklist "Mehrere auswählen (SPACE zum markieren)" 20 70 10 \
"${menu_list[@]}" 3>&1 1>&2 2>&3) || return
# Whiptail gibt die Auswahl in Anführungszeichen zurück, diese entfernen und Komma getrennt speichern
selected=$(echo $selected | tr -d '"' | tr ' ' ',')
# In Projekt-Config speichern
sed -i "s|^registry=.*|registry=$selected|" "$config_file"
}
# Schlüssel im Config-File ändern
change_project_setting() {
local config_file=$1
local key=$2
local current=$(grep "^$key=" "$config_file" | cut -d= -f2)
new_value=$(whiptail --inputbox "$key ändern (aktuell: $current)" 10 60 "$current" 3>&1 1>&2 2>&3) || return
sed -i "s|^$key=.*|$key=$new_value|" "$config_file"
}
# Aktuellen Editor aus global/config.json holen
get_editor_cmd() {
if [[ -f "$GLOBAL_CONFIG" ]]; then
jq -r '.editor // "nano"' "$GLOBAL_CONFIG"
else
echo "nano"
fi
}
# Projektdateien bearbeiten (Dateiauswahl + Editor)
edit_project_files() {
local project=$1
local project_dir="$PROJECTS_DIR/$project"
# Prüfen ob Projektordner existiert
if [[ ! -d "$project_dir" ]]; then
whiptail --msgbox "Projektordner nicht gefunden." 10 60
return
fi
# Editor aus globaler Config holen
local editor_cmd
editor_cmd=$(get_editor_cmd)
# dialog-Dateiauswahl
local file
file=$(dialog --title "Datei auswählen" --fselect "$project_dir/" 20 70 3>&1 1>&2 2>&3) || return
[[ -z "$file" ]] && return
# Datei im Editor öffnen
"$editor_cmd" "$file"
}
edit_project_architectures() {
local config_file=$1
local current=$(grep "^architectures=" "$config_file" | cut -d= -f2 | tr ',' ' ')
local all_archs=("amd64" "arm64" "armhf" "x86")
menu_list=()
for a in "${all_archs[@]}"; do
if [[ " $current " =~ " $a " ]]; then
menu_list+=("$a" "$a" ON)
else
menu_list+=("$a" "$a" OFF)
fi
done
selected=$(whiptail --title "Architekturen auswählen" --checklist "Mehrere auswählen" 20 70 10 "${menu_list[@]}" 3>&1 1>&2 2>&3) || return
selected=$(echo $selected | tr -d '"')
sed -i "s|^architectures=.*|architectures=$selected|" "$config_file"
}
edit_project_push() {
local config_file=$1
local current=$(grep "^push=" "$config_file" | cut -d= -f2)
local value="OFF"
[ "$current" == "yes" ] && value="ON"
selected=$(whiptail --title "Push aktivieren?" --checklist "Push auswählen" 10 50 1 push "Push aktivieren" $value 3>&1 1>&2 2>&3) || return
[[ $selected == *push* ]] && val="yes" || val="no"
sed -i "s|^push=.*|push=$val|" "$config_file"
}
edit_project_latest() {
local config_file=$1
local current=$(grep "^latest=" "$config_file" | cut -d= -f2)
local value="OFF"
[ "$current" == "yes" ] && value="ON"
selected=$(whiptail --title "Latest-Tag setzen?" --checklist "Latest auswählen" 10 50 1 latest "Latest setzen" $value 3>&1 1>&2 2>&3) || return
[[ $selected == *latest* ]] && val="yes" || val="no"
sed -i "s|^latest=.*|latest=$val|" "$config_file"
}
edit_project_auto_subversion() {
local config_file=$1
local current=$(grep "^auto_subversion=" "$config_file" | cut -d= -f2)
local value="OFF"
[ "$current" == "yes" ] && value="ON"
selected=$(whiptail --title "Subversion automatisch erhöhen?" --checklist "Auto Subversion auswählen" 10 50 1 auto "Automatisch erhöhen" $value 3>&1 1>&2 2>&3) || return
[[ $selected == *auto* ]] && val="yes" || val="no"
# falls auto_subversion key nicht existiert, hinzufügen
if grep -q "^auto_subversion=" "$config_file"; then
sed -i "s|^auto_subversion=.*|auto_subversion=$val|" "$config_file"
else
echo "auto_subversion=$val" >> "$config_file"
fi
}
# Hauptmenü - Registryverwaltung
registry_menu() {
while true; do
choice=$(whiptail --title "Registry-Verwaltung" --menu "Bitte wählen:" 20 70 10 \
1 "Registry erstellen" \
2 "Registry löschen" \
3 "Registry bearbeiten" \
0 "Zurück" \
3>&1 1>&2 2>&3) || return
case $choice in
1) create_registry ;;
2) delete_registry ;;
3) edit_registry ;;
0) return ;;
esac
done
}
# Registry anlegen
create_registry() {
local name url username password
name=$(whiptail --inputbox "Name der Registry (z.B. docker.io):" 10 60 3>&1 1>&2 2>&3) || return
[ -z "$name" ] && return
url=$(whiptail --inputbox "URL der Registry:" 10 60 3>&1 1>&2 2>&3) || return
username=$(whiptail --inputbox "Benutzername:" 10 60 3>&1 1>&2 2>&3) || return
password=$(whiptail --passwordbox "Passwort:" 10 60 3>&1 1>&2 2>&3) || return
mkdir -p "$REGISTRY_CONFIG_DIR/$name"
cat > "$REGISTRY_CONFIG_DIR/$name/config-file" <<EOF
url=$url
username=$username
password=$password
EOF
whiptail --msgbox "Registry '$name' wurde erstellt." 10 60
}
# Registry löschen
delete_registry() {
local registries
registries=$(ls "$REGISTRY_CONFIG_DIR" 2>/dev/null)
[ -z "$registries" ] && { whiptail --msgbox "Keine Registries vorhanden." 10 60; return; }
menu_list=()
for r in $registries; do
menu_list+=("$r" "")
done
local reg
reg=$(whiptail --menu "Registry zum Löschen auswählen:" 20 60 10 "${menu_list[@]}" 3>&1 1>&2 2>&3) || return
if whiptail --yesno "Registry $reg wirklich löschen?" 10 60; then
rm -rf "$REGISTRY_CONFIG_DIR/$reg"
whiptail --msgbox "Registry $reg wurde gelöscht." 10 60
fi
}
# Registry bearbeiten
edit_registry() {
local registries
registries=$(ls "$REGISTRY_CONFIG_DIR" 2>/dev/null)
[ -z "$registries" ] && { whiptail --msgbox "Keine Registries vorhanden." 10 60; return; }
menu_list=()
for r in $registries; do
menu_list+=("$r" "")
done
local reg
reg=$(whiptail --menu "Registry zum Bearbeiten auswählen:" 20 60 10 "${menu_list[@]}" 3>&1 1>&2 2>&3) || return
local config_file="$REGISTRY_CONFIG_DIR/$reg/config-file"
local url username password
url=$(grep "^url=" "$config_file" | cut -d= -f2)
username=$(grep "^username=" "$config_file" | cut -d= -f2)
password=$(grep "^password=" "$config_file" | cut -d= -f2)
# Eingaben ändern
url=$(whiptail --inputbox "URL:" 10 60 "$url" 3>&1 1>&2 2>&3) || return
username=$(whiptail --inputbox "Benutzername:" 10 60 "$username" 3>&1 1>&2 2>&3) || return
password=$(whiptail --passwordbox "Passwort:" 10 60 "$password" 3>&1 1>&2 2>&3) || return
cat > "$config_file" <<EOF
url=$url
username=$username
password=$password
EOF
whiptail --msgbox "Registry '$reg' wurde aktualisiert." 10 60
}
# Projektparameter laden
load_project_config() {
#project="$1"
config_file="$1"
if [[ -f "$config_file" ]]; then
echo "Lade Konfiguration für Projekt: $project"
image_name=$(grep "^image_name=" "$config_file" | cut -d= -f2)
dockerfile=$(grep "^dockerfile=" "$config_file" | cut -d= -f2)
context=$(grep "^context=" "$config_file" | cut -d= -f2)
version=$(grep "^version=" "$config_file" | cut -d= -f2)
architectures=$(grep "^architectures=" "$config_file" | cut -d= -f2)
registries=$(grep "^registries=" "$config_file" | cut -d= -f2)
# Architekturen vereinheitlichen → Kommata in Leerzeichen umwandeln
architectures="${architectures//,/ }"
# Mehrfache Leerzeichen säubern
architectures=$(echo "$architectures" | xargs)
echo "Geladene Konfiguration: image_name=$image_name, dockerfile=$dockerfile, context=$context, version=$version, architectures=$architectures, registries=$registries"
else
echo "Konfigurationsdatei $config_file nicht gefunden!"
exit 1
fi
}
# Gibt die URL einer Registry anhand des Config-Files zurück
get_registry_url() {
local reg=$1
local reg_file="$REGISTRY_CONFIG_DIR/$reg/config-file"
if [[ ! -f "$reg_file" ]]; then
echo ""
return
fi
grep -E '^url=' "$reg_file" | cut -d'=' -f2-
}
# Führt docker login für eine Registry anhand des Config-Files aus
registry_login() {
local reg=$1
local reg_file="$REGISTRY_CONFIG_DIR/$reg/config-file"
if [[ ! -f "$reg_file" ]]; then
echo "Registry-Konfiguration '$reg' fehlt!"
return 1
fi
local url username password
url=$(grep -E '^url=' "$reg_file" | cut -d'=' -f2-)
username=$(grep -E '^username=' "$reg_file" | cut -d'=' -f2-)
password=$(grep -E '^password=' "$reg_file" | cut -d'=' -f2-)
if [[ -z "$url" || -z "$username" || -z "$password" ]]; then
echo "Ungültige Registry-Konfig für $reg (url/username/password fehlt)!"
return 1
fi
echo "$password" | docker login "$url" -u "$username" --password-stdin
}
# Docker-Image bauen
build_image() {
local project=$1
local config_file="$PROJECT_CONFIG_DIR/$project/config-file"
load_project_config "$config_file"
local timestamp
timestamp=$(date +"%Y%m%d_%H%M%S")
local logfile="$LOGS_DIR/${project}_${timestamp}.log"
echo "==== Build gestartet: $(date) ====" | tee -a "$logfile"
echo "Projekt: $project" | tee -a "$logfile"
echo "Registries: $registry" | tee -a "$logfile"
echo "Image: $image_name" | tee -a "$logfile"
echo "Architekturen: $architectures" | tee -a "$logfile"
echo "Push: $push" | tee -a "$logfile"
echo "Version: $version" | tee -a "$logfile"
echo "Latest: $latest" | tee -a "$logfile"
echo "====================================" | tee -a "$logfile"
# Architekturen-Array vorbereiten
load_project_config "$project"
local platforms=""
local arch_array=()
# Split nach Leerzeichen
read -r -a arch_array <<< "$architectures"
for arch in "${arch_array[@]}"; do
case "$arch" in
amd64) platforms+="linux/amd64," ;;
arm64) platforms+="linux/arm64," ;;
armhf) platforms+="linux/arm/v7," ;;
x86) platforms+="linux/386," ;;
*) echo "WARNUNG: Unbekannte Architektur '$arch' wird ignoriert." ;;
esac
done
platforms="${platforms%,}"
echo "DEBUG platforms='$platforms'" | tee -a "$logfile"
if [[ -z "$platforms" ]]; then
echo "Keine Architektur ausgewählt. Build abgebrochen." | tee -a "$logfile"
return 1
fi
# Tags für alle Registries vorbereiten
IFS=',' read -ra reg_array <<< "$registry"
tags=()
for reg in "${reg_array[@]}"; do
reg=$(echo "$reg" | xargs) # trim
[[ -z "$reg" ]] && continue
# Docker-Login für Registry (falls Config vorhanden)
reg_config="$CONFIG_DIR/registries/$reg/config-file"
if [[ -f "$reg_config" ]]; then
reg_user=$(grep "^username=" "$reg_config" | cut -d= -f2)
reg_pass=$(grep "^password=" "$reg_config" | cut -d= -f2)
if [[ -n "$reg_user" && -n "$reg_pass" ]]; then
echo "$reg_pass" | docker login "$reg" -u "$reg_user" --password-stdin 2>>"$logfile" || {
echo "WARNUNG: Login bei $reg fehlgeschlagen!" | tee -a "$logfile"
}
fi
fi
tags+=("-t" "$reg/$image_name:$version")
if [[ "$latest" == "yes" ]]; then
tags+=("-t" "$reg/$image_name:latest")
fi
done
if [[ ${#tags[@]} -eq 0 ]]; then
echo "Keine Registry-Tags definiert. Build abgebrochen." | tee -a "$logfile"
return 1
fi
# Build-Befehl zusammenbauen
if [[ "$push" == "yes" ]]; then
cmd=(docker buildx build --platform "$platforms" "${tags[@]}" "$PROJECTS_DIR/$project" --push)
else
cmd=(docker buildx build --platform "$platforms" "${tags[@]}" "$PROJECTS_DIR/$project" --load)
fi
echo "${cmd[*]}" | tee -a "$logfile"
if "${cmd[@]}" >>"$logfile" 2>&1; then
echo "==== Build beendet: $(date) ====" | tee -a "$logfile"
# Auto-Subversion
if [[ "$auto_subversion" == "yes" ]]; then
local major minor
major=$(echo "$version" | cut -d. -f1)
minor=$(echo "$version" | cut -d. -f2)
minor=$((minor + 1))
new_version="${major}.${minor}"
sed -i "s/^version=.*/version=$new_version/" "$config_file"
echo "Subversion automatisch auf $new_version erhöht." | tee -a "$logfile"
fi
else
echo "==== Build fehlgeschlagen: $(date) ====" | tee -a "$logfile"
return 1
fi
}
# Logs ansehen (optional gefiltert nach Projekt)
view_logs() {
#ensure_logs_dir
local project_filter="${1:-}" # wenn Projekt übergeben, nur dessen Logs anzeigen
if [ -n "$project_filter" ]; then
logs=$(ls -1t "$LOGS_DIR/${project_filter}"_*.log 2>/dev/null | sed "s|$LOGS_DIR/||")
else
logs=$(ls -1t "$LOGS_DIR"/*.log 2>/dev/null | sed "s|$LOGS_DIR/||")
fi
[ -z "$logs" ] && { whiptail --msgbox "Keine Logs vorhanden." 10 60; return; }
menu_list=()
for l in $logs; do
menu_list+=("$l" "")
done
log_file=$(whiptail --menu "Log auswählen:" 20 70 12 "${menu_list[@]}" 3>&1 1>&2 2>&3) || return
# Editor aus globaler Config lesen
local editor=$(jq -r '.editor' "$GLOBAL_CONFIG")
${editor:-nano} "$LOGS_DIR/$log_file"
}
# Projektübersicht anzeigen
# Projektübersicht mit Aktionen
project_overview() {
local project=$1
local config_file="$PROJECT_CONFIG_DIR/$project/config-file"
load_project_config "$config_file"
# Registries als Array
IFS=' ' read -r -a regs <<< "$registry"
while true; do
local choice
choice=$(whiptail --title "Projektübersicht: $project" --menu "Parameter:" 20 70 12 \
"1" "Registries: ${registry}" \
"2" "Image-Name: $image_name" \
"3" "Architekturen: $architectures" \
"4" "Push: $push" \
"5" "Version: $version" \
"6" "Latest-Tag: $latest" \
"7" "Git-Repo: $git_repo" \
"B" "Bauen" \
"E" "Bearbeiten" \
"P" "Projektauswahl wechseln" \
"L" "Logs ansehen" \
"Z" "Zurück" \
3>&1 1>&2 2>&3) || return
case $choice in
B) build_image "$project" ;;
E) edit_project "$project" ;; # Bearbeitungsmenü für das Projekt
P) return ;; # zurück zur Projektauswahl
L) view_logs ;;
Z) return ;;
esac
done
}
# Projektauswahl für Image-Bauen
select_project_for_build() {
local projects
projects=$(ls "$PROJECT_CONFIG_DIR" 2>/dev/null)
[ -z "$projects" ] && { whiptail --msgbox "Keine Projekte vorhanden." 10 60; return; }
# Projekte für Menü vorbereiten (1-Spalte)
local menu_list=()
for p in $projects; do
menu_list+=("$p" "")
done
while true; do
local project
project=$(whiptail --title "Projekt auswählen" --menu "Projekt für Build auswählen:" 20 60 10 "${menu_list[@]}" 3>&1 1>&2 2>&3) || return
# Projektübersicht anzeigen
project_overview "$project"
done
}
# Menüpunkt im Hauptmenü
image_build_menu() {
select_project_for_build
}
# -------------------------
# Hauptmenü
# -------------------------
main_menu() {
while true; do
choice=$(whiptail --title "Image Builder" --menu "Bitte wählen:" 20 70 10 \
1 "Konfiguration" \
2 "Projektverwaltung" \
3 "Registryverwaltung" \
4 "Image-Bauen" \
5 "Image-Verwaltung" \
6 "Logs ansehen" \
0 "Beenden" \
3>&1 1>&2 2>&3) || exit 0
case $choice in
1) config_menu;;
2) project_menu;;
3) registry_menu ;;
4) image_build_menu;;
5) whiptail --msgbox "Image-Verwaltung (noch nicht implementiert)" 10 70;;
6) view_logs ;; # <-- hier globale Logs
0) exit 0;;
esac
done
}
# -------------------------
# Main
# -------------------------
ensure_dirs
ensure_prereqs
main_menu