- Auto-detects scripts via symlinks in ~/bin - Interactive script and server selection - Supports bashrc deployment - Handles lib/ dependencies - Includes security improvements 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
419 lines
11 KiB
Bash
Executable File
419 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# deploy.sh - Interaktives Deployment-Tool für esn-support-bash-snippets
|
|
# Maintainer: ljp
|
|
#
|
|
# Erkennt installierte Scripts in ~/bin und ermöglicht interaktive Auswahl
|
|
set -euo pipefail
|
|
|
|
# Prüfe LUSER Environment
|
|
LUSER="${LUSER:?Bitte LUSER setzen! (siehe go-Script)}"
|
|
|
|
# Script directory
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
BIN_DIR="$HOME/bin"
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage: deploy.sh
|
|
|
|
INTERAKTIVES DEPLOYMENT:
|
|
- Erkennt automatisch installierte Scripts in ~/bin
|
|
- Interaktive Auswahl der zu deployenden Scripts
|
|
- Interaktive Server-Auswahl (web, mx, logger, support)
|
|
- Optional: bashrc + modulare Configs deployment
|
|
|
|
FEATURES:
|
|
- Auto-Detection von Scripts in ~/bin
|
|
- Erkennung von Dependencies (lib/ directories)
|
|
- Dry-run Modus verfügbar
|
|
- Backup von bestehenden Files
|
|
|
|
ENVIRONMENT:
|
|
LUSER Required: Username für SSH-Verbindungen
|
|
USAGE
|
|
}
|
|
|
|
# Detect installierte Scripts in ~/bin (via Symlinks vom Installer)
|
|
detect_installed_scripts() {
|
|
local scripts=()
|
|
|
|
if [[ ! -d "$BIN_DIR" ]]; then
|
|
echo "Warnung: $BIN_DIR existiert nicht" >&2
|
|
return 0
|
|
fi
|
|
|
|
# Alle Symlinks in ~/bin die auf dieses Repository zeigen
|
|
while IFS= read -r -d '' script; do
|
|
local script_name=$(basename "$script")
|
|
|
|
# Nur Symlinks betrachten
|
|
if [[ -L "$script" ]]; then
|
|
local target=$(readlink "$script")
|
|
# Prüfe ob Symlink auf unser Repository zeigt
|
|
if [[ "$target" == "$SCRIPT_DIR"* ]]; then
|
|
scripts+=("$script_name")
|
|
fi
|
|
fi
|
|
done < <(find "$BIN_DIR" -maxdepth 1 -type l -print0 2>/dev/null || true)
|
|
|
|
printf '%s\n' "${scripts[@]}" | sort
|
|
}
|
|
|
|
# Finde Source-Pfad für Script-Namen
|
|
find_script_source() {
|
|
local script_name="$1"
|
|
|
|
# Suche in legacy/
|
|
if [[ -f "$SCRIPT_DIR/legacy/$script_name/$script_name.sh" ]]; then
|
|
echo "$SCRIPT_DIR/legacy/$script_name"
|
|
return 0
|
|
fi
|
|
|
|
# Suche in wh20/
|
|
if [[ -f "$SCRIPT_DIR/wh20/$script_name/$script_name.sh" ]]; then
|
|
echo "$SCRIPT_DIR/wh20/$script_name"
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
# Interaktive Script-Auswahl
|
|
select_scripts() {
|
|
local -a available_scripts
|
|
mapfile -t available_scripts < <(detect_installed_scripts)
|
|
|
|
if [[ "${#available_scripts[@]}" -eq 0 ]]; then
|
|
echo "Keine deployable Scripts in $BIN_DIR gefunden" >&2
|
|
return 1
|
|
fi
|
|
|
|
echo "=== Verfügbare Scripts in $BIN_DIR ==="
|
|
for i in "${!available_scripts[@]}"; do
|
|
printf "%2d) %s\n" $((i+1)) "${available_scripts[i]}"
|
|
done
|
|
echo
|
|
|
|
local selected_scripts=()
|
|
while true; do
|
|
echo -n "Script auswählen (Nummer, 'all' für alle, 'done' zum Beenden): "
|
|
read -r choice
|
|
|
|
case "$choice" in
|
|
done|q|quit|exit)
|
|
break
|
|
;;
|
|
all)
|
|
selected_scripts=("${available_scripts[@]}")
|
|
echo "Alle Scripts ausgewählt: ${selected_scripts[*]}"
|
|
break
|
|
;;
|
|
''|*[!0-9]*)
|
|
echo "Ungültige Eingabe. Bitte Nummer eingeben."
|
|
;;
|
|
*)
|
|
local idx=$((choice - 1))
|
|
if [[ $idx -ge 0 && $idx -lt ${#available_scripts[@]} ]]; then
|
|
local script="${available_scripts[idx]}"
|
|
if [[ ! " ${selected_scripts[*]} " =~ " ${script} " ]]; then
|
|
selected_scripts+=("$script")
|
|
echo "✓ $script hinzugefügt"
|
|
else
|
|
echo "Script bereits ausgewählt: $script"
|
|
fi
|
|
else
|
|
echo "Ungültige Nummer: $choice"
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
if [[ "${#selected_scripts[@]}" -gt 0 ]]; then
|
|
echo "Aktuell ausgewählt: ${selected_scripts[*]}"
|
|
fi
|
|
done
|
|
|
|
printf '%s\n' "${selected_scripts[@]}"
|
|
}
|
|
|
|
# Interaktive Target-Auswahl
|
|
select_target() {
|
|
echo "=== Server-Auswahl ==="
|
|
echo "1) web server"
|
|
echo "2) mx server"
|
|
echo "3) logger.in.nessus.at"
|
|
echo "4) support.in.easyname.com"
|
|
echo
|
|
|
|
local target_type=""
|
|
local target_number=""
|
|
|
|
while [[ -z "$target_type" ]]; do
|
|
echo -n "Server-Typ auswählen (1-4): "
|
|
read -r choice
|
|
|
|
case "$choice" in
|
|
1) target_type="web" ;;
|
|
2) target_type="mx" ;;
|
|
3) target_type="logger" ;;
|
|
4) target_type="support" ;;
|
|
*) echo "Ungültige Auswahl" ;;
|
|
esac
|
|
done
|
|
|
|
if [[ "$target_type" == "web" || "$target_type" == "mx" ]]; then
|
|
while [[ -z "$target_number" ]]; do
|
|
echo -n "${target_type} Server-Nummer eingeben: "
|
|
read -r number
|
|
if [[ "$number" =~ ^[0-9]+$ ]]; then
|
|
target_number="$number"
|
|
else
|
|
echo "Ungültige Nummer"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo "$target_type${target_number:+ $target_number}"
|
|
}
|
|
|
|
# Build SSH target from arguments
|
|
build_ssh_target() {
|
|
local target="$1"
|
|
local number="${2:-}"
|
|
|
|
case "$target" in
|
|
web)
|
|
[[ -n "$number" ]] || { echo "Fehler: 'web' benötigt Server-Nummer" >&2; return 1; }
|
|
echo "${LUSER}@web${number}.in.easyname.com"
|
|
;;
|
|
mx)
|
|
[[ -n "$number" ]] || { echo "Fehler: 'mx' benötigt Server-Nummer" >&2; return 1; }
|
|
echo "${LUSER}@mx${number}.in.easyname.com"
|
|
;;
|
|
logger)
|
|
echo "${LUSER}@logger.in.nessus.at"
|
|
;;
|
|
support)
|
|
echo "${LUSER}@support.in.easyname.com"
|
|
;;
|
|
*)
|
|
echo "Unbekanntes Target: $target" >&2
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Deploy single script to target
|
|
deploy_script() {
|
|
local script_name="$1"
|
|
local ssh_target="$2"
|
|
local dry_run="$3"
|
|
|
|
# Prüfe ob Script via Symlink installiert ist
|
|
local symlink_path="$BIN_DIR/$script_name"
|
|
if [[ ! -L "$symlink_path" ]]; then
|
|
echo "Fehler: $script_name ist nicht via Installer-Symlink installiert" >&2
|
|
return 1
|
|
fi
|
|
|
|
# Folge dem Symlink zum Original-Script
|
|
local original_script=$(readlink -f "$symlink_path")
|
|
local script_dir=$(dirname "$original_script")
|
|
|
|
echo "=== Deploying $script_name to $ssh_target ==="
|
|
echo " Source: $original_script"
|
|
|
|
if (( dry_run )); then
|
|
echo " [DRY-RUN] Würde kopieren:"
|
|
echo " $original_script -> ~/$script_name"
|
|
|
|
# Check für lib/ directory
|
|
if [[ -d "$script_dir/lib" ]]; then
|
|
echo " $script_dir/lib/ -> ~/lib_$script_name/"
|
|
fi
|
|
return 0
|
|
fi
|
|
|
|
# Kopiere das Original-Script
|
|
scp "$original_script" "$ssh_target:$script_name"
|
|
ssh "$ssh_target" "chmod +x $script_name"
|
|
|
|
# Kopiere lib/ directory falls vorhanden
|
|
if [[ -d "$script_dir/lib" ]]; then
|
|
echo " Deploying lib dependencies..."
|
|
scp -r "$script_dir/lib" "$ssh_target:lib_$script_name"
|
|
|
|
# Update Script um lib_<scriptname> zu verwenden
|
|
ssh "$ssh_target" "sed -i 's|\$SCRIPT_DIR/lib/|./lib_$script_name/|g' $script_name"
|
|
fi
|
|
|
|
echo " ✓ $script_name deployed successfully"
|
|
}
|
|
|
|
# Deploy bashrc and modular configs
|
|
deploy_bashrc() {
|
|
local ssh_target="$1"
|
|
local dry_run="$2"
|
|
local force="$3"
|
|
|
|
echo "=== Deploying bashrc to $ssh_target ==="
|
|
|
|
# Suche nach verfügbaren bashrc profiles
|
|
local profiles=()
|
|
while IFS= read -r -d '' profile_dir; do
|
|
profiles+=("$(basename "$profile_dir")")
|
|
done < <(find "$SCRIPT_DIR/bashprofiles" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null || true)
|
|
|
|
if [[ "${#profiles[@]}" -eq 0 ]]; then
|
|
echo " Keine bashprofiles gefunden - erstelle Default-Profile..."
|
|
if (( dry_run )); then
|
|
echo " [DRY-RUN] Würde Default-.bashrc mit modularer Struktur erstellen"
|
|
return 0
|
|
fi
|
|
|
|
# Erstelle Default .bashrc mit modularer Struktur
|
|
ssh "$ssh_target" 'cat > .bashrc << "EOF"
|
|
# .bashrc - Optimierte Bash-Konfiguration für easyname Support
|
|
# Generated with deployment script
|
|
|
|
##### History #####
|
|
HISTCONTROL=ignoredups:erasedups
|
|
HISTSIZE=50000
|
|
HISTFILESIZE=100000
|
|
HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
|
|
shopt -s histappend
|
|
shopt -s cmdhist
|
|
|
|
##### Prompt #####
|
|
if [[ "$TERM" != "dumb" ]]; then
|
|
PS1="\[\e[01;32m\]\u@\h\[\e[00m\]:\[\e[01;34m\]\w\[\e[00m\]\\$ "
|
|
fi
|
|
|
|
##### Modular configs #####
|
|
[[ -f ~/.bash_aliases ]] && source ~/.bash_aliases
|
|
[[ -f ~/.bash_env ]] && source ~/.bash_env
|
|
[[ -f ~/.bash_paths ]] && source ~/.bash_paths
|
|
|
|
##### Standard settings #####
|
|
if [[ -f /etc/bash_completion ]]; then
|
|
source /etc/bash_completion
|
|
fi
|
|
|
|
if [[ -x /usr/bin/dircolors ]]; then
|
|
eval "$(dircolors -b)"
|
|
fi
|
|
|
|
# Built with the help of Claude Code
|
|
EOF'
|
|
|
|
# Erstelle modulare Config-Files
|
|
ssh "$ssh_target" 'touch .bash_aliases .bash_env .bash_paths'
|
|
ssh "$ssh_target" 'echo "# Add your environment variables here" > .bash_env'
|
|
ssh "$ssh_target" 'echo "# Add your custom aliases here" > .bash_aliases'
|
|
ssh "$ssh_target" 'echo "# Add your PATH extensions here" > .bash_paths'
|
|
|
|
echo " ✓ Default bashrc mit modularer Struktur deployed"
|
|
return 0
|
|
fi
|
|
|
|
# Verwende erstes verfügbares Profil
|
|
local profile="${profiles[0]}"
|
|
echo " Using profile: $profile"
|
|
|
|
if (( dry_run )); then
|
|
echo " [DRY-RUN] Würde bashrc-Profile '$profile' kopieren"
|
|
return 0
|
|
fi
|
|
|
|
# Deploy bashrc profile
|
|
scp "$SCRIPT_DIR/bashprofiles/$profile/.bashrc" "$ssh_target:.bashrc"
|
|
|
|
echo " ✓ bashrc deployed successfully"
|
|
}
|
|
|
|
# MAIN - Interaktiver Modus
|
|
main() {
|
|
# Argument parsing für --help
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "Unbekannte Option: $1" >&2; usage; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
echo "=== easyname Support Scripts Deployment ==="
|
|
echo
|
|
|
|
# Schritt 1: Script-Auswahl
|
|
local -a selected_scripts
|
|
mapfile -t selected_scripts < <(select_scripts)
|
|
|
|
if [[ "${#selected_scripts[@]}" -eq 0 ]]; then
|
|
echo "Keine Scripts ausgewählt. Beende."
|
|
exit 0
|
|
fi
|
|
|
|
# Schritt 2: Target-Auswahl
|
|
local target_info
|
|
target_info=$(select_target)
|
|
read -r target_type target_number <<< "$target_info"
|
|
|
|
local ssh_target
|
|
ssh_target=$(build_ssh_target "$target_type" "$target_number")
|
|
|
|
# Schritt 3: Optionen
|
|
echo "=== Deployment-Optionen ==="
|
|
echo -n "Bashrc auch deployen? [y/N]: "
|
|
read -r deploy_bashrc_choice
|
|
local deploy_bashrc=0
|
|
[[ "$deploy_bashrc_choice" =~ ^[yY]$ ]] && deploy_bashrc=1
|
|
|
|
echo -n "Dry-run (nur anzeigen was gemacht würde)? [y/N]: "
|
|
read -r dry_run_choice
|
|
local dry_run=0
|
|
[[ "$dry_run_choice" =~ ^[yY]$ ]] && dry_run=1
|
|
|
|
# Schritt 4: Zusammenfassung
|
|
echo
|
|
echo "=== Deployment-Zusammenfassung ==="
|
|
echo "Target: $ssh_target"
|
|
echo "Scripts: ${selected_scripts[*]}"
|
|
[[ "$deploy_bashrc" -eq 1 ]] && echo "Bashrc: Ja"
|
|
[[ "$dry_run" -eq 1 ]] && echo "Modus: DRY-RUN"
|
|
echo
|
|
echo -n "Deployment starten? [y/N]: "
|
|
read -r confirm
|
|
|
|
if [[ ! "$confirm" =~ ^[yY]$ ]]; then
|
|
echo "Deployment abgebrochen."
|
|
exit 0
|
|
fi
|
|
|
|
# Schritt 5: Deployment ausführen
|
|
echo
|
|
echo "=== Deployment wird ausgeführt ==="
|
|
|
|
# Deploy bashrc if requested
|
|
if (( deploy_bashrc )); then
|
|
deploy_bashrc "$ssh_target" "$dry_run"
|
|
fi
|
|
|
|
# Deploy scripts
|
|
for script in "${selected_scripts[@]}"; do
|
|
deploy_script "$script" "$ssh_target" "$dry_run" || {
|
|
echo "Fehler beim Deployment von $script" >&2
|
|
exit 1
|
|
}
|
|
done
|
|
|
|
echo
|
|
echo "=== Deployment abgeschlossen ==="
|
|
echo "Target: $ssh_target"
|
|
[[ "$deploy_bashrc" -eq 1 ]] && echo "✓ bashrc deployed"
|
|
echo "✓ Scripts deployed: ${selected_scripts[*]}"
|
|
[[ "$dry_run" -eq 1 ]] && echo "(DRY-RUN - nichts wurde tatsächlich deployed)"
|
|
}
|
|
|
|
# Script starten
|
|
main "$@"
|
|
|
|
# Built with the help of Claude Code |