Update Kernel Patch #26

Closed
opened 2026-06-01 20:51:45 +00:00 by chinux · 1 comment
Owner

Ziel

Den Proxmox-Kernel-Cleanup als backend-owned Action integrieren: das Skript liegt im Backend, wird bei Bedarf via agent.run_script auf den PVE-Host geschickt und dort ausgefuehrt. Kein neuer Code auf der Node - der Agent bleibt unveraendert.

Trigger (proaktiv, statt nur beim Update)

  • Primaer: proaktiv ueber den /boot-Watch aus #64 - Node-Flag kernel_cleanup_recommended (bei /boot use_percent >= Schwellwert) blendet Badge/Button ein.
  • Zusaetzlich: manuelle Maintenance-Action am Node + Einstieg beim Node-/Kernel-Update.
  • Voraussetzung: #64 liefert die /boot-Telemetrie (Datenquelle).

Architektur

  • Skript als Asset: server/assets/proxmox-kernel-cleanup.sh (unten, unveraendert uebernehmen).
  • Backend-Service server/services/kernel_cleanup.py: laedt das Asset, schickt es via agent.run_script an den Node, haengt den Modus an, faengt stdout + exit-code ab.
  • Agent: 0 Aenderungen (generisches agent.run_script, Kanal 1, root auf dem Host).

Ablauf (Dry-Run-First-Modal)

  1. Dry-Run: Skript OHNE --apply -> stdout (Orphan-Liste + df -h /boot) zurueck -> Modal zeigt Vorschau, was geloescht wuerde.
  2. Bestaetigung: User bestaetigt im Modal -> Skript mit --apply --yes (das --yes ersetzt die TTY-Rueckfrage; bestaetigt wird im UI).
  3. Ergebnis: stdout + df -h /boot zurueck ins Modal; bei erfolgreichem Purge feuert notify()-Event kernel_cleanup (info).

Endpoint

POST /api/nodes/{node}/kernel-cleanup mit { "apply": bool } -> { stdout, exit_code, removed: [...] }. apply=false = Dry-Run.

notify()

Neues Event kernel_cleanup in EVENT_DEFS (server/services/notifications.py), severity info, feuert backend-seitig nach erfolgreichem --apply mit gepurgten Kerneln.

Guards / Sicherheit

  • Nur PVE-Nodes (Host-Operation), nicht auf VMs/CTs.
  • Nie auto-apply - immer Dry-Run -> explizite Bestaetigung.
  • Sicherheitsnetze des Skripts unangetastet (MIN_KEEP=2, laufender Kernel wird nie geloescht, Abbruch-Checks, proxmox-boot-tool-Guard).

Haertung (Bezug #56)

  • Nicht jeder Host hat eine separate /boot-Partition -> Fallback/skip sauber behandeln (siehe #64).

Bezug

  • #64: liefert die /boot-Telemetrie + Watch-Flag (proaktiver Trigger).
  • #56: Haertung (OS-/Partitions-Varianten).

Branch

feat/kernel-cleanup-backend-action


Skript (unveraendert als Asset server/assets/proxmox-kernel-cleanup.sh uebernehmen)

#!/usr/bin/env bash
#
# proxmox-kernel-cleanup.sh
# ------------------------------------------------------------
# Räumt verwaiste Kernel aus /boot und der Paket-DB auf einem
# Proxmox-VE-Host auf. Behalten werden:
#   - der aktuell laufende Kernel (uname -r)        -> NIE löschen
#   - alle von `proxmox-boot-tool kernel list` ausgewählten Kernel
#
# Default = Dry-Run (zeigt nur, was passieren würde).
# Erst mit  --apply  wird wirklich gelöscht/gepurged.
#
# Sicherheitsnetz: bricht ab, wenn weniger als MIN_KEEP Kernel
# übrig blieben oder der laufende Kernel als "verwaist" gälte.
# ------------------------------------------------------------

set -uo pipefail   # bewusst KEIN -e: purge/rm dürfen mal nonzero liefern

# --- Konfiguration ------------------------------------------------
MIN_KEEP=2          # so viele Kernel müssen mindestens übrig bleiben
APPLY=0
ASSUME_YES=0

# --- Args ---------------------------------------------------------
for arg in "$@"; do
  case "$arg" in
    --apply)   APPLY=1 ;;
    --yes|-y)  ASSUME_YES=1 ;;
    -h|--help)
      cat <<EOF
Usage: $0 [--apply] [--yes]

  (ohne Optionen)  Dry-Run: zeigt nur, was gelöscht würde
  --apply          Führt das Aufräumen wirklich aus
  --yes, -y        Keine Rückfrage (für Cron/Automatisierung)

Behalten werden immer der laufende Kernel und alle von
proxmox-boot-tool ausgewählten Kernel.
EOF
      exit 0 ;;
    *) echo "Unbekannte Option: $arg" >&2; exit 2 ;;
  esac
done

# --- Vorbedingungen ----------------------------------------------
[[ $EUID -eq 0 ]] || { echo "Bitte als root ausführen." >&2; exit 1; }
command -v proxmox-boot-tool >/dev/null || { echo "proxmox-boot-tool fehlt – kein Proxmox-Host?" >&2; exit 1; }

log()  { printf '%s\n' "$*"; }
hr()   { printf '%.0s-' {1..60}; printf '\n'; }

# --- Keep-Set ermitteln ------------------------------------------
RUNNING="$(uname -r)"

# Versionszeilen aus proxmox-boot-tool (alles was mit Ziffer.Ziffer beginnt)
mapfile -t SELECTED < <(proxmox-boot-tool kernel list 2>/dev/null | grep -E '^[0-9]+\.[0-9]+' || true)

declare -A KEEP
KEEP["$RUNNING"]=1
for v in "${SELECTED[@]}"; do
  [[ -n "$v" ]] && KEEP["$v"]=1
done

# --- Alle vorhandenen Kernel (Files) sammeln ---------------------
declare -A PRESENT
for f in /boot/vmlinuz-*-pve; do
  [[ -e "$f" ]] || continue
  PRESENT["${f#/boot/vmlinuz-}"]=1
done

# --- Aufteilen in keep / orphan ----------------------------------
ORPHANS=()
for v in "${!PRESENT[@]}"; do
  [[ -n "${KEEP[$v]:-}" ]] || ORPHANS+=("$v")
done

KEEP_COUNT=0
for v in "${!PRESENT[@]}"; do
  [[ -n "${KEEP[$v]:-}" ]] && ((KEEP_COUNT++))
done

# --- Übersicht ----------------------------------------------------
hr
log "Laufender Kernel : $RUNNING  (wird IMMER behalten)"
log "Behalten         : $(printf '%s ' "${!KEEP[@]}")"
log "Gefunden in /boot: ${#PRESENT[@]} Kernel"
log "Verwaist         : ${#ORPHANS[@]} -> ${ORPHANS[*]:-(keine)}"
hr
df -h /boot
hr

# --- Sicherheitschecks -------------------------------------------
if [[ ${#ORPHANS[@]} -eq 0 ]]; then
  log "Nichts aufzuräumen. Alles sauber. ✔"
  exit 0
fi

if [[ $KEEP_COUNT -lt $MIN_KEEP ]]; then
  log "ABBRUCH: Es blieben nur $KEEP_COUNT Kernel übrig (Minimum $MIN_KEEP)." >&2
  exit 1
fi

for v in "${ORPHANS[@]}"; do
  if [[ "$v" == "$RUNNING" ]]; then
    log "ABBRUCH: Laufender Kernel würde gelöscht – sollte nie passieren." >&2
    exit 1
  fi
done

# --- Dry-Run-Ausgabe ---------------------------------------------
if [[ $APPLY -eq 0 ]]; then
  log "DRY-RUN. Es würde Folgendes passieren:"
  for v in "${ORPHANS[@]}"; do
    log "  rm /boot/{vmlinuz,initrd.img,System.map,config}-$v"
  done
  log "  apt --fix-broken install"
  log "  apt purge  <proxmox-kernel-Pakete der obigen Versionen>"
  log "  update-initramfs -u -k all && proxmox-boot-tool refresh && update-grub"
  log ""
  log ">> Zum Ausführen erneut mit  --apply  starten."
  exit 0
fi

# --- Bestätigung --------------------------------------------------
if [[ $ASSUME_YES -eq 0 ]]; then
  read -r -p "Wirklich ${#ORPHANS[@]} verwaiste Kernel entfernen? [j/N] " ans || ans=""
  case "$ans" in
    j|J|y|Y) : ;;
    *) log "Abgebrochen."; exit 0 ;;
  esac
fi

# --- 1) Files weg (schafft sofort Platz) -------------------------
log ">> Lösche verwaiste /boot-Dateien ..."
for v in "${ORPHANS[@]}"; do
  rm -f "/boot/vmlinuz-$v" "/boot/initrd.img-$v" \
        "/boot/System.map-$v" "/boot/config-$v"
done
df -h /boot

# --- 2) Hängenden dpkg/apt-Vorgang reparieren --------------------
log ">> apt --fix-broken install ..."
apt-get --fix-broken install -y

# --- 3) Verwaiste Kernel-Pakete purgen ---------------------------
log ">> Suche zugehörige Pakete ..."
PKGS=()
for v in "${ORPHANS[@]}"; do
  while read -r pkg; do
    [[ -n "$pkg" ]] && PKGS+=("$pkg")
  done < <(dpkg-query -W -f='${Package}\n' \
            "proxmox-kernel-$v" "proxmox-kernel-$v-signed" \
            "pve-kernel-$v" "pve-kernel-$v-signed" 2>/dev/null)
done

if [[ ${#PKGS[@]} -gt 0 ]]; then
  log ">> Purge: ${PKGS[*]}"
  apt-get purge -y "${PKGS[@]}"
else
  log ">> Keine passenden Pakete installiert (nur Dateileichen) – ok."
fi

apt-get autoremove --purge -y

# --- 4) Bootloader/Initramfs aktualisieren -----------------------
log ">> update-initramfs / boot-tool refresh / update-grub ..."
update-initramfs -u -k all || true
proxmox-boot-tool refresh   || true
update-grub                 || true

hr
log "Fertig. ✔"
df -h /boot
proxmox-boot-tool kernel list
## Ziel Den Proxmox-Kernel-Cleanup als **backend-owned Action** integrieren: das Skript liegt im Backend, wird bei Bedarf via `agent.run_script` auf den PVE-Host geschickt und dort ausgefuehrt. **Kein neuer Code auf der Node** - der Agent bleibt unveraendert. ## Trigger (proaktiv, statt nur beim Update) - Primaer: proaktiv ueber den `/boot`-Watch aus #64 - Node-Flag `kernel_cleanup_recommended` (bei `/boot use_percent >= Schwellwert`) blendet Badge/Button ein. - Zusaetzlich: manuelle Maintenance-Action am Node + Einstieg beim Node-/Kernel-Update. - Voraussetzung: #64 liefert die `/boot`-Telemetrie (Datenquelle). ## Architektur - **Skript** als Asset: `server/assets/proxmox-kernel-cleanup.sh` (unten, unveraendert uebernehmen). - **Backend-Service** `server/services/kernel_cleanup.py`: laedt das Asset, schickt es via `agent.run_script` an den Node, haengt den Modus an, faengt stdout + exit-code ab. - **Agent:** 0 Aenderungen (generisches `agent.run_script`, Kanal 1, root auf dem Host). ## Ablauf (Dry-Run-First-Modal) 1. **Dry-Run:** Skript OHNE `--apply` -> stdout (Orphan-Liste + `df -h /boot`) zurueck -> Modal zeigt Vorschau, was geloescht wuerde. 2. **Bestaetigung:** User bestaetigt im Modal -> Skript mit `--apply --yes` (das `--yes` ersetzt die TTY-Rueckfrage; bestaetigt wird im UI). 3. **Ergebnis:** stdout + `df -h /boot` zurueck ins Modal; bei erfolgreichem Purge feuert `notify()`-Event `kernel_cleanup` (info). ## Endpoint `POST /api/nodes/{node}/kernel-cleanup` mit `{ "apply": bool }` -> `{ stdout, exit_code, removed: [...] }`. `apply=false` = Dry-Run. ## notify() Neues Event `kernel_cleanup` in `EVENT_DEFS` (`server/services/notifications.py`), severity `info`, feuert backend-seitig nach erfolgreichem `--apply` mit gepurgten Kerneln. ## Guards / Sicherheit - **Nur PVE-Nodes** (Host-Operation), nicht auf VMs/CTs. - **Nie auto-apply** - immer Dry-Run -> explizite Bestaetigung. - Sicherheitsnetze des Skripts unangetastet (`MIN_KEEP=2`, laufender Kernel wird nie geloescht, Abbruch-Checks, `proxmox-boot-tool`-Guard). ## Haertung (Bezug #56) - Nicht jeder Host hat eine separate `/boot`-Partition -> Fallback/`skip` sauber behandeln (siehe #64). ## Bezug - **#64**: liefert die `/boot`-Telemetrie + Watch-Flag (proaktiver Trigger). - **#56**: Haertung (OS-/Partitions-Varianten). ## Branch `feat/kernel-cleanup-backend-action` --- ## Skript (unveraendert als Asset `server/assets/proxmox-kernel-cleanup.sh` uebernehmen) ```bash #!/usr/bin/env bash # # proxmox-kernel-cleanup.sh # ------------------------------------------------------------ # Räumt verwaiste Kernel aus /boot und der Paket-DB auf einem # Proxmox-VE-Host auf. Behalten werden: # - der aktuell laufende Kernel (uname -r) -> NIE löschen # - alle von `proxmox-boot-tool kernel list` ausgewählten Kernel # # Default = Dry-Run (zeigt nur, was passieren würde). # Erst mit --apply wird wirklich gelöscht/gepurged. # # Sicherheitsnetz: bricht ab, wenn weniger als MIN_KEEP Kernel # übrig blieben oder der laufende Kernel als "verwaist" gälte. # ------------------------------------------------------------ set -uo pipefail # bewusst KEIN -e: purge/rm dürfen mal nonzero liefern # --- Konfiguration ------------------------------------------------ MIN_KEEP=2 # so viele Kernel müssen mindestens übrig bleiben APPLY=0 ASSUME_YES=0 # --- Args --------------------------------------------------------- for arg in "$@"; do case "$arg" in --apply) APPLY=1 ;; --yes|-y) ASSUME_YES=1 ;; -h|--help) cat <<EOF Usage: $0 [--apply] [--yes] (ohne Optionen) Dry-Run: zeigt nur, was gelöscht würde --apply Führt das Aufräumen wirklich aus --yes, -y Keine Rückfrage (für Cron/Automatisierung) Behalten werden immer der laufende Kernel und alle von proxmox-boot-tool ausgewählten Kernel. EOF exit 0 ;; *) echo "Unbekannte Option: $arg" >&2; exit 2 ;; esac done # --- Vorbedingungen ---------------------------------------------- [[ $EUID -eq 0 ]] || { echo "Bitte als root ausführen." >&2; exit 1; } command -v proxmox-boot-tool >/dev/null || { echo "proxmox-boot-tool fehlt – kein Proxmox-Host?" >&2; exit 1; } log() { printf '%s\n' "$*"; } hr() { printf '%.0s-' {1..60}; printf '\n'; } # --- Keep-Set ermitteln ------------------------------------------ RUNNING="$(uname -r)" # Versionszeilen aus proxmox-boot-tool (alles was mit Ziffer.Ziffer beginnt) mapfile -t SELECTED < <(proxmox-boot-tool kernel list 2>/dev/null | grep -E '^[0-9]+\.[0-9]+' || true) declare -A KEEP KEEP["$RUNNING"]=1 for v in "${SELECTED[@]}"; do [[ -n "$v" ]] && KEEP["$v"]=1 done # --- Alle vorhandenen Kernel (Files) sammeln --------------------- declare -A PRESENT for f in /boot/vmlinuz-*-pve; do [[ -e "$f" ]] || continue PRESENT["${f#/boot/vmlinuz-}"]=1 done # --- Aufteilen in keep / orphan ---------------------------------- ORPHANS=() for v in "${!PRESENT[@]}"; do [[ -n "${KEEP[$v]:-}" ]] || ORPHANS+=("$v") done KEEP_COUNT=0 for v in "${!PRESENT[@]}"; do [[ -n "${KEEP[$v]:-}" ]] && ((KEEP_COUNT++)) done # --- Übersicht ---------------------------------------------------- hr log "Laufender Kernel : $RUNNING (wird IMMER behalten)" log "Behalten : $(printf '%s ' "${!KEEP[@]}")" log "Gefunden in /boot: ${#PRESENT[@]} Kernel" log "Verwaist : ${#ORPHANS[@]} -> ${ORPHANS[*]:-(keine)}" hr df -h /boot hr # --- Sicherheitschecks ------------------------------------------- if [[ ${#ORPHANS[@]} -eq 0 ]]; then log "Nichts aufzuräumen. Alles sauber. ✔" exit 0 fi if [[ $KEEP_COUNT -lt $MIN_KEEP ]]; then log "ABBRUCH: Es blieben nur $KEEP_COUNT Kernel übrig (Minimum $MIN_KEEP)." >&2 exit 1 fi for v in "${ORPHANS[@]}"; do if [[ "$v" == "$RUNNING" ]]; then log "ABBRUCH: Laufender Kernel würde gelöscht – sollte nie passieren." >&2 exit 1 fi done # --- Dry-Run-Ausgabe --------------------------------------------- if [[ $APPLY -eq 0 ]]; then log "DRY-RUN. Es würde Folgendes passieren:" for v in "${ORPHANS[@]}"; do log " rm /boot/{vmlinuz,initrd.img,System.map,config}-$v" done log " apt --fix-broken install" log " apt purge <proxmox-kernel-Pakete der obigen Versionen>" log " update-initramfs -u -k all && proxmox-boot-tool refresh && update-grub" log "" log ">> Zum Ausführen erneut mit --apply starten." exit 0 fi # --- Bestätigung -------------------------------------------------- if [[ $ASSUME_YES -eq 0 ]]; then read -r -p "Wirklich ${#ORPHANS[@]} verwaiste Kernel entfernen? [j/N] " ans || ans="" case "$ans" in j|J|y|Y) : ;; *) log "Abgebrochen."; exit 0 ;; esac fi # --- 1) Files weg (schafft sofort Platz) ------------------------- log ">> Lösche verwaiste /boot-Dateien ..." for v in "${ORPHANS[@]}"; do rm -f "/boot/vmlinuz-$v" "/boot/initrd.img-$v" \ "/boot/System.map-$v" "/boot/config-$v" done df -h /boot # --- 2) Hängenden dpkg/apt-Vorgang reparieren -------------------- log ">> apt --fix-broken install ..." apt-get --fix-broken install -y # --- 3) Verwaiste Kernel-Pakete purgen --------------------------- log ">> Suche zugehörige Pakete ..." PKGS=() for v in "${ORPHANS[@]}"; do while read -r pkg; do [[ -n "$pkg" ]] && PKGS+=("$pkg") done < <(dpkg-query -W -f='${Package}\n' \ "proxmox-kernel-$v" "proxmox-kernel-$v-signed" \ "pve-kernel-$v" "pve-kernel-$v-signed" 2>/dev/null) done if [[ ${#PKGS[@]} -gt 0 ]]; then log ">> Purge: ${PKGS[*]}" apt-get purge -y "${PKGS[@]}" else log ">> Keine passenden Pakete installiert (nur Dateileichen) – ok." fi apt-get autoremove --purge -y # --- 4) Bootloader/Initramfs aktualisieren ----------------------- log ">> update-initramfs / boot-tool refresh / update-grub ..." update-initramfs -u -k all || true proxmox-boot-tool refresh || true update-grub || true hr log "Fertig. ✔" df -h /boot proxmox-boot-tool kernel list ```
Author
Owner

Second Claude succeed

Verifiziert: services/kernel_cleanup.py run_kernel_cleanup schickt das Skript via agent.run_script (backend-owned, Agent unverändert); apply=False=Dry-Run, apply=True=--apply --yes; bei erfolgreichem Purge feuert notify("kernel_cleanup"). Endpoint admin_router.py:703, Skript-Asset server/assets/proxmox-kernel-cleanup.sh, Frontend-Modal (Commit 9a73c38).

**Second Claude succeed** ✅ Verifiziert: `services/kernel_cleanup.py` `run_kernel_cleanup` schickt das Skript via **`agent.run_script`** (backend-owned, Agent unverändert); `apply=False`=Dry-Run, `apply=True`=`--apply --yes`; bei erfolgreichem Purge feuert `notify("kernel_cleanup")`. Endpoint `admin_router.py:703`, Skript-Asset `server/assets/proxmox-kernel-cleanup.sh`, Frontend-Modal (Commit 9a73c38).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
chinux/theProx#26
No description provided.