237 lines
7.4 KiB
Bash
237 lines
7.4 KiB
Bash
#!/bin/bash
|
|
|
|
# === PVE Kernel Cleaner Script ===
|
|
# Kompatibel mit EFI & BIOS, erkennt ZFS Pools und prüft Belegung
|
|
# Erkennt auch Subscription-Status
|
|
# Autor: Patrick Perlbach
|
|
# Datum: 2025-06-20
|
|
|
|
# Farben & Formatierung
|
|
bold=$(tput bold)
|
|
reset=$(tput sgr0)
|
|
green=$(tput setaf 2)
|
|
yellow=$(tput setaf 3)
|
|
red=$(tput setaf 1)
|
|
|
|
# Einstellungen
|
|
ZFS_DATASET="rpool/ROOT/pve-1" # ZFS Dataset für Boot-Pool
|
|
SNAPSHOT_TAG="pve-kernel-cleaner" # Tag für Snapshots
|
|
MAX_SNAPSHOTS=5 # Max. Snapshots behalten
|
|
LOGFILE="/var/log/pve-kernel-cleaner.log" # Logdatei
|
|
TIMESTAMP=$(date +%Y-%m-%d-%H-%M-%S) # Zeitstempel für Snapshots
|
|
dry_run="false" # Standard: kein Testlauf
|
|
|
|
# Hilfe anzeigen
|
|
show_help() {
|
|
cat << EOF
|
|
Verwendung: $(basename "$0") [OPTIONEN]
|
|
|
|
Dieses Script entfernt alte Proxmox Kernel und behält eine definierte Anzahl neuer Kernel.
|
|
|
|
Optionen:
|
|
-k NUM Anzahl der Kernel, die behalten werden sollen (Standard: 1)
|
|
-d Testmodus (Dry-Run), keine Änderungen werden vorgenommen
|
|
-h Diese Hilfe anzeigen
|
|
EOF
|
|
}
|
|
|
|
# Systeminformationen anzeigen
|
|
kernel_info() {
|
|
echo "=== PVE Kernel Cleaner Script ==="
|
|
echo ""
|
|
echo "Systeminformationen:"
|
|
echo "─────────────────────────────"
|
|
|
|
current_kernel=$(uname -r)
|
|
kernels_installed=($(dpkg --list | awk '/proxmox-kernel-.*-pve-signed/ {print $2}' | sort -V))
|
|
num_kernels=${#kernels_installed[@]}
|
|
|
|
if [ -d /sys/firmware/efi ]; then
|
|
echo "Boot-Modus: EFI"
|
|
else
|
|
echo "Boot-Modus: Legacy (BIOS)"
|
|
fi
|
|
|
|
if [ -f /etc/os-release ]; then
|
|
os_name=$(grep PRETTY_NAME /etc/os-release | cut -d= -f2 | tr -d '"')
|
|
echo "Betriebssystem: $os_name"
|
|
fi
|
|
|
|
if zfs list $ZFS_DATASET &>/dev/null; then
|
|
boot_used=$(zfs get -H -o value used $ZFS_DATASET)
|
|
boot_avail=$(zfs get -H -o value available $ZFS_DATASET)
|
|
echo "ZFS Boot-Pool ($ZFS_DATASET): benutzt $boot_used, verfügbar $boot_avail"
|
|
else
|
|
boot_df=($(df -h /boot | tail -1))
|
|
echo "Boot-Partition: ${boot_df[2]} verwendet von ${boot_df[1]} verfügbar (${boot_df[4]} voll)"
|
|
fi
|
|
|
|
echo "Aktueller Kernel: $current_kernel"
|
|
echo "Installierte Proxmox-Kernel ($num_kernels):"
|
|
for k in "${kernels_installed[@]}"; do
|
|
echo " - $k"
|
|
done
|
|
echo "─────────────────────────────"
|
|
echo ""
|
|
}
|
|
|
|
# Prüfe Subscription-Status der APT-Repositories
|
|
check_apt_repos() {
|
|
echo "APT-Repositories:"
|
|
repo_files=$(find /etc/apt/ -name "*.list")
|
|
|
|
if grep -rq "enterprise.proxmox.com" $repo_files; then
|
|
echo "PVE Enterprise Repository (Subscription) ist aktiv"
|
|
elif grep -rq "no-subscription" $repo_files; then
|
|
echo "PVE No-Subscription Repository ist aktiv"
|
|
else
|
|
echo "Kein bekanntes PVE Repository aktiv, prüfe apt-Sources manuell"
|
|
fi
|
|
echo ""
|
|
}
|
|
|
|
# Snapshot erstellen, falls ZFS vorhanden
|
|
create_snapshot() {
|
|
if zfs list $ZFS_DATASET &>/dev/null; then
|
|
snapshot_name="${ZFS_DATASET}@${SNAPSHOT_TAG}-${TIMESTAMP}"
|
|
echo "Erstelle ZFS Snapshot: $snapshot_name"
|
|
if [ "$dry_run" = "false" ]; then
|
|
zfs snapshot "$snapshot_name" || echo "${red}Snapshot konnte nicht erstellt werden!${reset}"
|
|
else
|
|
echo "Snapshot würde erstellt: $snapshot_name"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Alte Snapshots löschen, wenn zu viele vorhanden sind
|
|
cleanup_snapshots() {
|
|
if zfs list $ZFS_DATASET &>/dev/null; then
|
|
snapshots=($(zfs list -t snapshot -o name -s creation | grep "$SNAPSHOT_TAG" | grep "^${ZFS_DATASET}@${SNAPSHOT_TAG}" || true))
|
|
num_snapshots=${#snapshots[@]}
|
|
if (( num_snapshots > MAX_SNAPSHOTS )); then
|
|
delete_count=$((num_snapshots - MAX_SNAPSHOTS))
|
|
echo "Es sind $num_snapshots Snapshots mit Tag '$SNAPSHOT_TAG' vorhanden. Entferne $delete_count alte Snapshot(s)."
|
|
for ((i=0; i<delete_count; i++)); do
|
|
snap_to_delete=${snapshots[i]}
|
|
echo "Lösche Snapshot: $snap_to_delete"
|
|
if [ "$dry_run" = "false" ]; then
|
|
zfs destroy "$snap_to_delete" || echo "${red}Snapshot $snap_to_delete konnte nicht gelöscht werden!${reset}"
|
|
else
|
|
echo "Snapshot würde gelöscht: $snap_to_delete"
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Alte Kernel entfernen
|
|
remove_old_kernels() {
|
|
local keep=$1
|
|
echo "Es werden alle außer den $keep neuesten Kernel entfernt..."
|
|
|
|
# Nur pve-signed Kernel-Pakete auflisten, sortiert
|
|
mapfile -t kernels < <(dpkg --list | awk '/proxmox-kernel-.*-pve-signed/ {print $2}' | sort -V)
|
|
local total=${#kernels[@]}
|
|
|
|
echo "Gefundene Kernel: $total"
|
|
|
|
if (( total <= keep )); then
|
|
echo "Es gibt nicht mehr Kernel als die zu behaltenden ($keep). Kein Kernel wird entfernt."
|
|
return
|
|
fi
|
|
|
|
# Kernel die entfernt werden sollen
|
|
to_remove=("${kernels[@]:0:total-keep}")
|
|
num_to_remove=${#to_remove[@]}
|
|
|
|
echo "Folgende Kernel werden entfernt:"
|
|
for k in "${to_remove[@]}"; do
|
|
echo " - $k"
|
|
done
|
|
|
|
# Nutzer fragt, ob er entfernen will
|
|
printf "${bold}[!]${reset} Möchten Sie die ${bold}$num_to_remove${reset} ausgewählten PVE Kernel entfernen? [y/N]: "
|
|
read -n 1 -r
|
|
printf "\n"
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
echo "Abbruch durch Benutzer."
|
|
return
|
|
fi
|
|
|
|
# ZFS Snapshot vor dem Löschen
|
|
create_snapshot
|
|
|
|
# Kernel entfernen
|
|
for k in "${to_remove[@]}"; do
|
|
printf "${bold}[-]${reset} Entferne Kernel-Paket: $k ... "
|
|
if [ "$dry_run" = "false" ]; then
|
|
apt-get purge -y "$k" > /dev/null 2>&1
|
|
if [ $? -eq 0 ]; then
|
|
printf "${green}Fertig!${reset}\n"
|
|
else
|
|
printf "${red}Fehler!${reset}\n"
|
|
fi
|
|
else
|
|
echo "Kernel würde entfernt: $k"
|
|
fi
|
|
done
|
|
|
|
# Grub aktualisieren
|
|
printf "${bold}[*]${reset} Aktualisiere GRUB... "
|
|
if [ "$dry_run" = "false" ]; then
|
|
if command -v proxmox-boot-tool >/dev/null 2>&1; then
|
|
proxmox-boot-tool refresh > /dev/null 2>&1
|
|
else
|
|
update-grub > /dev/null 2>&1
|
|
fi
|
|
printf "${green}Fertig!${reset}\n"
|
|
else
|
|
echo "GRUB würde aktualisiert werden."
|
|
fi
|
|
|
|
# Alte Snapshots bereinigen
|
|
cleanup_snapshots
|
|
}
|
|
|
|
main() {
|
|
local keep=1
|
|
|
|
# Optionen parsen
|
|
while getopts ":k:dh" opt; do
|
|
case $opt in
|
|
k) keep=$OPTARG ;;
|
|
d) dry_run="true" ;;
|
|
h) show_help; exit 0 ;;
|
|
\?) echo "Ungültige Option: -$OPTARG" >&2; show_help; exit 1 ;;
|
|
:) echo "Option -$OPTARG benötigt ein Argument." >&2; show_help; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
kernel_info
|
|
check_apt_repos
|
|
|
|
echo "[-] PVE kernel search complete!"
|
|
echo ""
|
|
|
|
# Kernel-Keeping abfragen
|
|
read -rp "Wie viele Kernel sollen behalten werden? [Standard: $keep]: " user_keep
|
|
if [[ "$user_keep" =~ ^[0-9]+$ ]]; then
|
|
keep=$user_keep
|
|
fi
|
|
|
|
remove_old_kernels "$keep"
|
|
|
|
# Anzahl Snapshots am Ende anzeigen
|
|
if zfs list $ZFS_DATASET &>/dev/null; then
|
|
snapshots=($(zfs list -t snapshot -o name -s creation | grep "$SNAPSHOT_TAG" | grep "^${ZFS_DATASET}@${SNAPSHOT_TAG}" || true))
|
|
num_snapshots=${#snapshots[@]}
|
|
echo ""
|
|
echo "Anzahl vorhandener Snapshots mit Tag '$SNAPSHOT_TAG': $num_snapshots"
|
|
fi
|
|
|
|
echo ""
|
|
echo "Fertig."
|
|
}
|
|
|
|
main "$@"
|