Proxmox - Tools / BUG Fixes Workarounds / Tipps und Tricks

Hier kommen alle Themen Rund um Fehlerbehebungen und Workarounds rein

Proxmox 7 - Deutsche Windows ISO nach installation keine Netzwerkkarten nur Ausrufungszeichen

Bei einem Proxmox update auf Version 7 können keine neuen Netzwerkkarten hinzugefügt werden und wenn doch Fehler 53
klassenkonfiguration wird von windows noch eingerichtet

Siehe Schreenshot.

IMG_20221022_194808.jpg

Abhilfe q35 auf version 5.1 umstellen.

Screenshot 2022-10-22 at 19-58-06 vservwohn - Proxmox Virtual Environment.png

Beim neustart / starten könnte es einen Bluescreen geben.
einfach nochmals starten, läuft dann.
Fertig

Proxmox/Debian bei älteren Monitoren - Out of Range

Hat man am Server einen Monitor aus den 2000er angeschlossen und der unterstützt die akteullen modi nicht mehr.
Per SSH einloggen oder gleich nach der installation im grub nomodeset stezten.


Für GRUP legacy boot oder EFI ohne ZFS

nano /etc/default/grub

FÜR EFI Boot mit ZFS

nano /etc/kernel/cmdline

hinter quiet einfach 

nomodeset
schreiben

Beispiel

GRUB_CMDLINE_LINUX_DEFAULT="quiet nomodeset"

solltet ihr noch mehr custom paremter haben stehen die natürlich dahinter

zum Schluss für legacy oder nur efi

update-grub

für EFI mit ZFS

pve-efiboot-tool refresh

Dann den Server neustarten fertig.
Nun haben wir auch endlich Bild mit nem alten Monitor


Proxmox ZFS Offline Mount mit PVE Install DVD/STICK

Beschreibung

Wie oft hat man das Problem zum Beispiel einen Proxmoxhost wo die Grafikkarte durchgereicht ist und so die Bedienung mit Tastatur und Maus nicht möglich ist. Es war immer nur möglich den Host per ssh und Weboberfläche zu steuern.
Jetzt kommt ein ein neues Mainboard oder neue Grafikkarte rein und schon ändert sich der Name der Netzwerkkarte.
Und nun? Mit der PVE DVD Starten das ZFS Mounten die Netzwerkkonfig ändern undfertig.

DVD Starten

Von der PVE Install DVD/Stick starten und den Debug Mode auswählen.

Bildschirmfoto vom 2023-01-03 08-09-59.png

Nun sind wir in einem Debug Terminal.
in diesem können wir aber noch nicht wirkliche Befhele absetzten.
Deswegen hier mit STRG+D drücken um in das zweite Terminal zu gelangen.

Bildschirmfoto vom 2023-01-03 08-16-16.png

Hier können wir nun Befehle absetzten.

Bildschirmfoto vom 2023-01-03 08-17-01.png

Netzwerkkarte ermitteln und Tastatursprache festlegen

Als erstes wollen wir wissen wir wissen wie unsere Netzwerkkarte heißt, das hat zwar nichts mit ZFS zu tun, allerings soll es hier ja auch einen Sinn machen.

ip a

In unserem Beispiel ens18

Bildschirmfoto vom 2023-01-03 08-18-06.png

Die Tastaursprache legen wir mit 
dpkg-reconfigure keyboard-configuration

fest.

Nun werden wir nach dem Tastaturmodell gefragt.

Bildschirmfoto vom 2023-01-03 08-21-06.png

Mit Enter gehts auf die nächste Seite. Ich nehme die 71 Generic 105 intl..
Solange enter drücken bis Keyboardmodel dort steht, 71 eintippen enter drücken

Bildschirmfoto vom 2023-01-03 08-31-22.png

Nun das Layout, hier die 11 keine toten Tasten

Bildschirmfoto vom 2023-01-03 08-26-02.png

Nun ALT-GR Funktionstaste hier standard 1 wählen

Bildschirmfoto vom 2023-01-03 08-27-44.png

Nun den Compose Key wählen (Ich habe keinen) da eure Einstellung wählen.
Also bei mir die 1

Bildschirmfoto vom 2023-01-03 08-28-43.png

Da wir keinen X-Server haben hier nein (no) wählen

Bildschirmfoto vom 2023-01-03 08-29-26.png

Vielleicht klappts bei euch bir mir nicht.

Legende für English

\ = #
- = ß
/ = -
? = shift + -
z = y
y = z
* = shift + 8
@ = shift + 2
# = shift + 3
^ = shift + 6
& = shift + 7
( = shift + 9
) = shift + 0
_ = shift + ß
: = shift + ö

ZFS einbinden

Pools auflisten.

Mit diesem Befehl werden alle pools aufgelistet ohne diese zu importieren. Villeicht möchte man ja nur einen bestimmten pool importieren. Wir haben hier nur einen. nämlich rpool.

zpool import -a

Hier bekommen wir nämlcih einen Hinweis, das der Pool schon mal woanders gemountet war. Diese machen wir uns zu nutze um die Pools aufzulisten.

Bildschirmfoto vom 2023-01-03 08-51-30.png

Möchte man explicit einen pool importieren gibt man dessen namen an und nicht -a

zpool import rpool

Die selbe Meldung halt nur für den Pool

Bildschirmfoto vom 2023-01-03 08-52-47.png
Da wir diesen aber importieren wollfen den Paramter -f hinter her.

zpool import rpool -f

Nun schauen wir uns den Status an

zpool status

Dem Pool gehts gut

Bildschirmfoto vom 2023-01-03 08-54-53.png

Mit dem Befehl

mount

sehen wir, wo er den Pool gemountet hat. Diese mount points unbedingt merken.

Bildschirmfoto vom 2023-01-03 08-59-03.png

Das gleiche geht auch mit

zfs list

Bildschirmfoto vom 2023-01-03 09-02-10.png

Wie wir sehen ist der PVE-1 eigentlich auf / gemountet, was natürlich nicht geht, da ja schon / vom system vergeben ist.
Also müssen wir den Mountpoint umbiegen

zfs set mountpoint=/mnt rpool/ROOT/pve-1

Bildschirmfoto vom 2023-01-03 09-05-59.png

Nun wurde das Verzeichnis geremounted. Siehe mittels

mount

Bildschirmfoto vom 2023-01-03 09-07-24.png

Nun können wir zum Beispiel die Netzwerkkarte editieren.
Das root Verzeichnis vom ZFS Pool wurde in /mnt gemountet

nano /mnt/etc/network/interfaces

Tadaaa unsere Netzwerk konfig. Diese oder noch andere sachen ändern

Bildschirmfoto vom 2023-01-03 09-08-45.png

und zum Schluss den Mountpoint wieder zrucüksetzen auf /

Dazu auf / wechseln, denn das Verzeichnis darf nicht offen sein

cd /

Nun zurücksetzten

zfs set mountpoint=/ rpool/ROOT/pve-1

Mit

mount

nochmals überprüfen.

Bildschirmfoto vom 2023-01-03 09-13-32.png

Passt. Fertig.
neustarten mit STRG+D

und dann abort auswählen.

Bildschirmfoto vom 2023-01-03 09-14-46.png

Nun im Terminal wieder STRG+D drücken
Das System startet neu.

Beim Starten bekommen wir wieder den Hinweis das der pool fremdimportiert wurde.

Bildschirmfoto vom 2023-01-03 09-17-41.png

Wie in der Beschreibung ja auch zu lesen

zpool import rpool -f

Bildschirmfoto vom 2023-01-03 09-19-02.png

Nun wieder STRG+D

Und die Kiste läuft.

Bildschirmfoto vom 2023-01-03 09-20-04.png


Jetzt einloggen und nochmal neustarten.

Bildschirmfoto vom 2023-01-03 09-21-18.png

Läuft so durch

Bildschirmfoto vom 2023-01-03 09-20-04.png

fertig

LXC Conatiner startet nach Installation einer Software die als Dienst startet nicht mehr. (AppArmor)

Beschreibung

LXC Conatiner startet nach Installation einer Software die als Dienst startet nicht mehr.
So sieht das Bild aus. Einfach ein schwarzes terminal wo wir reinschreiben können.
Auswahl_001.png

Vorbereitung

Damit wir info bekommen, warum das ding nicht startet müssen wir in den Option des Containers die Console von tty auf Console umstellen.

Dazu auf Optionen des Containers und Doppelklick auf Console

Auswahl_002.png

Nun aus der Liste /dev(console auswählen und ok

Auswahl_003.png

Wenn wir jetzt den Container neu starten und ein neues Konsolenfenter aufmachen bekommen wir infos.

Auswahl_004.png

Nun melden wir uns mit unserem Kennwort an und sheen wir sind als root eingeloggt

Auswahl_005.png

Nun mit journalctl -xe schauen was Sache ist. Dazu scrollen wir hoch bis zum Fehler.

emd[86]: /sbin/apparmor_parser: Unable to replace "lsb_release".  Permission de>
emd[93]: /sbin/apparmor_parser: Unable to replace "/usr/bin/man".  Permission d>
emd[92]: /sbin/apparmor_parser: Unable to replace "/usr/lib/NetworkManager/nm-d>
emd[96]: Skipping profile in /etc/apparmor.d/disable: usr.sbin.rsyslogd
emd[94]: /sbin/apparmor_parser: Unable to replace "tcpdump".  Permission denied>
emd[118]: /sbin/apparmor_parser: Unable to replace "lsb_release".  Permission d>
emd[121]: /sbin/apparmor_parser: Unable to replace "kmod".  Permission denied; >
emd[121]: /sbin/apparmor_parser: Unable to replace "nvidia_modprobe".  Permissi>
emd[133]: /sbin/apparmor_parser: Unable to replace "/usr/bin/man".  Permission >
emd[131]: /sbin/apparmor_parser: Unable to replace "/usr/lib/NetworkManager/nm->
emd[139]: Skipping profile in /etc/apparmor.d/disable: usr.sbin.rsyslogd
emd[135]: /sbin/apparmor_parser: Unable to replace "tcpdump".  Permission denie>
emd[77]: Error: At least one profile failed to load
pparmor.service: Main process exited, code=exited, status=1/FAILURE

scroll right

replace "lsb_release".  Permission denied; attempted to load a profile while >
o replace "/usr/bin/man".  Permission denied; attempted to load a profile while>
o replace "/usr/lib/NetworkManager/nm-dhcp-client.action".  Permission denied; >
or.d/disable: usr.sbin.rsyslogd
o replace "tcpdump".  Permission denied; attempted to load a profile while conf>
to replace "lsb_release".  Permission denied; attempted to load a profile while>
to replace "kmod".  Permission denied; attempted to load a profile while confin>
to replace "nvidia_modprobe".  Permission denied; attempted to load a profile w>
to replace "/usr/bin/man".  Permission denied; attempted to load a profile whil>
to replace "/usr/lib/NetworkManager/nm-dhcp-client.action".  Permission denied;>
mor.d/disable: usr.sbin.rsyslogd
to replace "tcpdump".  Permission denied; attempted to load a profile while con>
led to load

scroll right
ied; attempted to load a profile while confined?
nied; attempted to load a profile while confined?
cp-client.action".  Permission denied; attempted to load a profile while confin>

 attempted to load a profile while confined?
nied; attempted to load a profile while confined?
ttempted to load a profile while confined?
n denied; attempted to load a profile while confined?
enied; attempted to load a profile while confined?
hcp-client.action".  Permission denied; attempted to load a profile while confi>

; attempted to load a profile while confined?


In dem Conatiner dann apparmor deaktivieren

systemctl disable apparmor

Dann sollte die Kiste starten.
Allerdings rate ich genau wegen solchen Dingen von Containern ab und empfehle KVM in Verbindung mit cloudinit.



Proxmox Wartungsmodus / Maintenance Mode - Diasable / Enable VMS at Start

Beschreibung

Man möchte den Server mehrmals neustarten, dann nervt es doch, wenn alle VMs/CTs mit starten.
Mit folgendem Script kann man das ein und auschalten

Installation des scripte

Auf den Server einloggen (sollte es ein Cluster sein, braucht das nur auf eine Node gepackt werden)
Nun eine Neue Datei erstellen

nano /root/save_boot_state.sh

Den Inhalt einfügen

#!/bin/bash
# boot-save-disable.sh
# Speichert alle onboot=1 VMs/CTs und deaktiviert sie

SAVEFILE="/root/boot-state.txt"
> "$SAVEFILE"

echo "=== Speichere Boot-Status ==="

for conf in /etc/pve/qemu-server/*.conf /etc/pve/lxc/*.conf; do
    [ -f "$conf" ] || continue
    if grep -q "^onboot: 1" "$conf"; then
        id=$(basename "$conf" .conf)
        type="vm"
        [[ "$conf" == *"/lxc/"* ]] && type="ct"
        echo "$type $id" >> "$SAVEFILE"
        sed -i 's/^onboot: 1/onboot: 0/' "$conf"
        echo "  Deaktiviert: $type $id"
    fi
done

echo ""
echo "Gespeichert in: $SAVEFILE"
echo "$(wc -l < "$SAVEFILE") Einträge"

 

Ausführbar machen

chmod +x /root/save_boot_state.sh

Wiederherstellung Script

nano /root/restore-boot-state.sh

Inhalt

#!/bin/bash
# boot-restore.sh
# Stellt onboot=1 für alle gespeicherten VMs/CTs wieder her

SAVEFILE="/root/boot-state.txt"

if [ ! -f "$SAVEFILE" ]; then
    echo "Fehler: $SAVEFILE nicht gefunden!"
    exit 1
fi

echo "=== Stelle Boot-Status wieder her ==="

while read -r type id; do
    if [ "$type" = "vm" ]; then
        conf="/etc/pve/qemu-server/${id}.conf"
    else
        conf="/etc/pve/lxc/${id}.conf"
    fi

    if [ -f "$conf" ]; then
        if grep -q "^onboot:" "$conf"; then
            sed -i 's/^onboot: 0/onboot: 1/' "$conf"
        else
            echo "onboot: 1" >> "$conf"
        fi
        echo "  Aktiviert: $type $id"
    else
        echo "  FEHLER: $conf nicht gefunden"
    fi
done < "$SAVEFILE"

echo ""
echo "Fertig."

Ausführbar machen

chmod +x /root/restore_boot_state.sh

Status script

nano /root/status_boot_state.sh

Inhalt

#!/bin/bash
# boot-status.sh
# Zeigt aktuellen onboot-Status aller VMs/CTs

SAVEFILE="/root/boot-state.txt"

echo "=== Aktueller onboot-Status ==="
echo ""
printf "%-6s %-6s %-8s %s\n" "Typ" "ID" "onboot" "Name"
echo "-------------------------------------"

for conf in /etc/pve/qemu-server/*.conf /etc/pve/lxc/*.conf; do
    [ -f "$conf" ] || continue
    id=$(basename "$conf" .conf)
    type="vm"; [[ "$conf" == *"/lxc/"* ]] && type="ct"
    name=$(grep "^name:" "$conf" | awk '{print $2}')
    [ -z "$name" ] && name=$(grep "^hostname:" "$conf" | awk '{print $2}')
    onboot=$(grep "^onboot:" "$conf" | awk '{print $2}')
    [ -z "$onboot" ] && onboot="0"
    printf "%-6s %-6s %-8s %s\n" "$type" "$id" "$onboot" "${name:-}"
done

echo ""
if [ -f "$SAVEFILE" ]; then
    echo "Gespeicherte Einträge in $SAVEFILE: $(wc -l < "$SAVEFILE")"
else
    echo "Kein Savefile vorhanden ($SAVEFILE)"
fi

Ausführbar machen

chmod +x /root/status_boot_state.sh

 

 





Proxmox Host aus VM herunterfahren

Beschreibung

Es gibt Situtationen, zum Beispiel bei einer VM mit durchgereichter Grafikkare und USB Ports, wo man den ganzen Host mit einem Doppelklick oder einem Befehl gerne herunterfahren möchte.
Damit die VMs auch das Signal bekommen zum herunterfahren muss der qemu Agent installiert sein.
Siehe : Proxmox - Qemu Agent installation

Proxmox aus einer Windows VM herunterfahren

Als erstes downloaden wir uns plink von der putty Seite.
https://www.putty.org

Nun auf Download klicken

Bildschirmfoto vom 2023-02-25 08-42-48.png

Dort nun runterscrollen bis wir bei plink.exe ankommen.
Dort für eure Architektur plink.exe anklicken

Bildschirmfoto vom 2023-02-25 08-43-19.png

Da ich ein 64 Bit Windows habe, nehme ich 64bit x86 und klicke es an.
Nun klicken wir aud das Ordnersymbol neben dem download

Bildschirmfoto vom 2023-02-25 08-44-50.png
Nun öffnet sich der Download Ordner

Bildschirmfoto vom 2023-02-25 08-47-23.png

Wir schneiden die plink exe aus

Bildschirmfoto vom 2023-02-25 08-47-49.png

und legen sie in Program Files wieder ein

Bildschirmfoto vom 2023-02-25 08-48-53.png

Drücken dann auf fortsetzen

Bildschirmfoto vom 2023-02-25 08-49-05.png

Nun liegt die plink.exe im Programmverzeichnis.
Nun legen wir eine neue Verknüpfung auf dem Desktop an.
Rechtklick auf den Desktop -> Neu -> Verknüpfung

Bildschirmfoto vom 2023-02-25 08-50-51.png

Nun auf den Durchsuchen button klicken

Bildschirmfoto vom 2023-02-25 08-51-02.png

Nun AUf Dieser PC -> Laufwerk C-> Proragmme gehen

Bildschirmfoto vom 2023-02-25 08-51-45.png

Nun runterscrollen bis plink.exe

Bildschirmfoto vom 2023-02-25 08-51-56.png

Nun auf OK

Bildschirmfoto vom 2023-02-25 08-52-01.png

Nun steht der Pfad dazu im Textfeld, hier noch NICHT auf weiter klicken, weil wir plink ein paar Paramter übergeben wollen

Bildschirmfoto vom 2023-02-25 08-54-15.png

Diese wären

"C:\Program Files\plink.exe" -ssh -pw <proxmoxpasswort> root@<proxmoxhost> poweroff

Beispiel: "C:\Program Files\plink.exe" -ssh -pw 12345678 root@192.168.0.100 poweroff

Dann sähe das so aus, und nun auf weiter

Bildschirmfoto vom 2023-02-25 08-57-37.png

Jetz dem Kind noch ein Namen geben zum Beispiel Herunterfahren und dann auf Fertigstellen klicken

Bildschirmfoto vom 2023-02-25 08-59-30.png

Nun haben wir eine Verknüpfung mit herunterfahren.
Doppelklick drauf dier Proxmoxhost fährt runter und beendet die VMs

Bildschirmfoto vom 2023-02-25 08-59-42.png
Nun kommt die Frage ob der Key im cache store gespeichert werden soll. Mit y bestätigen

Bildschirmfoto vom 2023-02-25 09-04-00.png
Nun kommt acces granted. Einfach enter drücken

Bildschirmfoto vom 2023-02-25 09-04-31.png

Nach jedem Ausführen kommt die frage ob ausgeführt werden soll. Einfach mit enter bestätigen.
nun fahren die VMs und dann der HOst  herunter.


Proxmox - Es lassen sich keine Snapshots anlegen

Beschreibung:

Man hat einen proxmox Host und nur den Standard local-lvm Storage.
Aber aus irgendeinem Grund kann man keine Snapchots anlegen.
Fehler : 

The current guest configuration does not support taking new snapshots

Auswahl_129.png

Vorrausetzungen für Snap-Shots:

  1. Keine laufenden Migrationen oder Aufgaben: Wenn eine VM migriert oder andere Aufgaben ausgeführt werden, kann es nicht möglich sein, einen Snapshot zu erstellen. Sie müssen alle laufenden Aufgaben abschließen, bevor Sie einen Snapshot erstellen können.

  2. Unterstützung auf Dateisystemebene: Das Dateisystem der VM muss Snapshots unterstützen. Zum Beispiel werden Snapshots auf der EXT4- und XFS-Dateisystemebene nicht unterstützt.
    LVM-Thin (Nicht LVM, LVM ünterstützt keine Snapshots) und ZFS unterstützen jedoch Snapshots.
    Ausnahme bei EXT4:

    Nur wenn das Disk-Image der VM im QCOW2-Format (QEMU Copy-On-Write) ist.

    QCOW2 ist ein von QEMU entwickeltes Dateiformat, das Snapshots auf Dateiebene unterstützt. Diese Snapshots sind unabhängig vom zugrundeliegenden Dateisystem und funktionieren daher auf Ext4. Sie sind auch wesentlich flexibler und einfacher zu verwalten als LVM-Snapshots.

    Bitte beachten Sie jedoch, dass das QCOW2-Format in einigen Situationen eine geringere Leistung aufweisen kann als RAW-Disk-Images oder LVM-basierte Speicher.
    Es ist wichtig, die spezifischen Anforderungen und die Performance Ihrer Umgebung zu berücksichtigen, wenn Sie sich für ein Disk-Image-Format entscheiden.

  3. Disk-Konfiguration: In einigen Fällen kann die Konfiguration der VM-Festplatte die Erstellung von Snapshots verhindern. Zum Beispiel unterstützen Virtio-IDE uns SATA nicht das Erzeugen von Live-Snapshots (Snapshots, während die VM läuft).

  4. QEMU-Gastagent: Der QEMU-Gastagent sollte installiert und laufend sein, wenn Sie versuchen, einen laufenden Snapshot zu erstellen (auch als Live-Snapshot bezeichnet). Der Gastagent ermöglicht eine bessere Interaktion zwischen dem Host und der VM, einschließlich der korrekten Verwaltung von Snapshots.

Wenn Ihre VM diese Anforderungen erfüllt, sollten Sie in der Lage sein, Snapshots zu erstellen. Wenn Sie trotzdem weiterhin Probleme haben, sollten Sie die Fehlermeldung und das VM-Setup genauer untersuchen.


Proxmox 7 installation hängt bei 99% make system bootable

Beschreibung:

Das System bleibt stehen bei 99% make System Bootable.
Bei einem Intel Board s5520hc soll das wohl standard so sein. Da das EFI broken ist.
Kann kein NVRAM schreiben.

IMG_20230609_085444.jpg

Was hab Ich probiert, sollte probiert werden:


Festplatte an Onboardcontroller gehängt -> kein Erfolg
Anderen Stick verwendet -> kein Erfolg
Proxmox 6.4 iso installtiert, dann inplace update durchgeführt -> kein Erfolg
(falls über Ventoy gebootet werden soll, hier wird die ISO nicht gefunden. Also vom Stick der mit Schreiber für Datenträger beschrieben wurde, sonst findet er die iso nicht)
Holzhammer Methode: Festplatte in anderen Rechner hängen, dort installieren.
Wieder zurückbauen, Netzwerkkonfig ändern. -> kein erfolg

Was brachte Erflog:

Installieren bis Fehler 99%
Dann ausschalten, von der Proxmox ISO Starten Advanced Debug Modus auswählen.
Dann STRG+D drücken damit ein System geladen wird.
Dann nochmals STRG+D damit ein System mit richtigem Terminal geladen wird

Dann nochmals STRG+D damit Netzwerk geladen wird un der Installer.
Dann im installer auf abort klciken
Nun sind wir wieder in der shell.

apt update
apt install openssh-server

Nun die sshd config anpassen

nano /etc/ssh/ssd_config

und root zugriff erlauben

danach

service ssh restart

Nun das root Passwort neu setzten

passwd

nun mit

ip a

IP-Adresse ausgeben und per ssh verbinden.

Schlüsel akzeptierun, kennwort eingeben.
Wir sind drin ;-)

Auswahl_154.png

Nun den rpool mounten, wenn nichts zurück gegeben wird, hats geklappt

zpool import -f -R /mnt rpool

Nun die Verzeichnisse mounten /dev /proc /sys

mount --rbind /dev  /mnt/rpool/ROOT/pve-1/dev
mount --rbind /proc /mnt/rpool/ROOT/pve-1/proc
mount --rbind /sys  /mnt/rpool/ROOT/pve-1/sys

Nun müssen wir noch unsere EFI Partion herausfinden.
in unserem Beispiel ist  das Laufwerk sda, bei euch anpassen

gdisk /dev/sda

Nun p drücken um die Partitionen angezeigt zu bekommen

isk /dev/sda: 937703088 sectors, 447.1 GiB
Model: KINGSTON SA400S3
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): E8AF2BF1-95B5-445D-89E4-E08361D101A3
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 937703054
Partitions will be aligned on 8-sector boundaries
Total free space is 0 sectors (0 bytes)

Number  Start (sector)    End (sector)  Size       Code  Name
   1              34            2047   1007.0 KiB  EF02  
   2            2048         2099199   1024.0 MiB  EF00  
   3         2099200       937703054   446.1 GiB   BF01  

Die Partition mit EF00 ist unsere Efi Boot Partition
in unserem Beispiel dann /dev/sda2

Nun mounten wir die Partition in /boot/efi unser chroot umgebung

mount /dev/sda2 /mnt/rpool/ROOT/pve-1/boot/efi

Danach chrooten wir uns mit einer bash ins root Verzeichnis unserer Proxmox installtion

chroot /mnt/rpool/ROOT/pve-1 /bin/bash

Nun installieren wir endlich grub neu, aber ohne nv-ram

grub-install --no-nvram

Ausgabe:

root@proxmox:/# grub-install --no-nvram
Installing for x86_64-efi platform.
Installation finished. No error reported.
root@proxmox:/# 

Grub aktualisieren

update-grub

Ausgabe, bedeutet er schaut nicht nach anderen systemen, diese werden nicht hinzugefügt

root@proxmox:/# update-grub
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-5.15.102-1-pve
Found memtest86+ image: /ROOT/pve-1@/boot/memtest86+.bin
Found memtest86+ multiboot image: /ROOT/pve-1@/boot/memtest86+_multiboot.bin
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
done

Dann exit.
Am richtigen Server wierder STRG+D drücken, dann startet der Server neu

 

aot install grub-efi-amd64

Nun haben wir ein System mit tools.
Dort den grubinstall neu konfiguriern

dpkg-reconfigure grub-efi-amd64




Nun herausfinden welche unsere EFI Partition ist.

lsblk -o +FSTYPE

Die wählen wo VFAT steht, also /dev/sda2
Ausgabe:

Nun den rpool mounten

    zpool import -f -R /mnt rpool

Nun die Verzeichnisse mounten die wir brauchen

mount -o rbind /proc /mnt/rpool/ROOT/pve-1/proc
mount -o rbind /sys /mnt/rpool/ROOT/pve-1/sys
mount -o rbind /dev /mnt/rpool/ROOT/pve-1/dev
mount -o rbind /run /mnt/rpool/ROOT/pve-1/run

Nun in das root Verzeichnis vom pve-1 chrooten

chroot /mnt/rpool/ROOT/pve-1 /bin/bash



Jetzt den Bootloader neu installieren.

Dazu müssen wir vorher die EFI Partion mounten.
In meinem Beispiel ist das die 1GB partition

mount /dev/sda2 /mnt

Nun können wir den Befehl zum Grub installieren absetzten



Anlegen / Clonen einer ARM64 VM Fehler

Beschreibung:

Ab Version 8.1 muss das Firmware Paket für arm64 manuell nachinstalliert werden.
Sonst bekommtman diesen Fehler:

TASK ERROR: clone failed: EFI base image '/usr/share/pve-edk2-firmware//AAVMF_CODE.fd' not found

Lösung:

Folgendes Paket manuell installieren

apt install pve-edk2-firmware-aarch64

Fertig.
nun lässt sich die VM wieder erstellen / clonen


LXC Conatiner - Routen beim start setzten,da post in interfaces nicht geht

Beschreibung:

leider unterstützen LCX keine einträge in der /etc/interfaces weil die bei jedem Start wieder gelöscht werden.
Abhilfe mit einem Systemd service

Einrichtung

Ein script erstellen was die route anlegt:

nano /usr/local/bin/set-routes.sh

Inhalt

route add route add <zieladresse oder netz> gw <gateway> dev <netzwerkkarte>
route add 185.26.156.118 gw 222.222.0.7 dev eth1

bei einem netz sähe das so aus

bei einem 28er netz
route add 185.26.156.0/28 gw 222.222.0.7 dev eth1
bei einem 24 netz
route add 185.26.156.24 gw 222.222.0.7 dev eth1

also nun das script


#!/bin/bash
route add route add <zieladresse oder netz> gw <gateway> dev <netzwerkkarte>



Script ausführbar machen

chmod +x /usr/local/bin/set-routes.sh

Nun einen Systemd Service Datei anlegen

nano /etc/systemd/system/set-routes.service

Inhalt:

 

[Unit]
Description=Set custom routes after network is up
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/set-routes.sh
RemainAfterExit=true

[Install]
WantedBy=multi-user.target

Nun den systemctl neuladen den Dienst aktivieren und starten

systemctl daemon-reload
systemctl enable set-routes.service
systemctl start set-routes.service

Fertig

Ceph Upgrade von Pacific 17.2.7 auf reef 18.2.2 osd starten nicht

Beschreibung:


Beim Upgrade von 17.2.7 auf 18.2.2 starten die OSD nicht.


Lösung:


Erstmal auf 18.2.1 downgraden, dann warten bis die osds gestartet sind.

apt install ceph=18.2.1-pve2 ceph-mon=18.2.1-pve2 ceph-mgr=18.2.1-pve2 ceph-osd=18.2.1-pve2 ceph-mds=18.2.1-pve2 ceph-base=18.2.1-pve2 librados2=18.2.1-pve2 ceph-mgr-modules-core=18.2.1-pve2 libradosstriper1=18.2.1-pve2 libsqlite3-mod-ceph=18.2.1-pve2 librados2=18.2.1-pve2 librbd1=18.2.1-pve2 ceph-common=18.2.1-pve2 libcephfs2=18.2.1-pve2 python3-cephfs=18.2.1-pve2 python3-ceph-argparse=18.2.1-pve2 python3-ceph-common=18.2.1-pve2 python3-rados=18.2.1-pve2 python3-rbd=18.2.1-pve2 python3-rgw=18.2.1-pve2 librgw2=18.2.1-pve2 ceph-fuse=18.2.1-pve2 ceph-volume=18.2.1-pve2

Nun die min version zurück auf quincy setzten

ceph osd require-osd-release quincy

Danach leider die node neustarten, da aber eh alle OSDs offline sind, wäre das bei der Node auch egal.
Sollte das auch nicht gehen dann downgrade auf 17.2.7 zurück

apt install ceph=17.2.7-pve3 ceph-mon=17.2.7-pve3 ceph-mgr=17.2.7-pve3 ceph-osd=17.2.7-pve3 ceph-mds=17.2.7-pve3 ceph-base=17.2.7-pve3 librados2=17.2.7-pve3 ceph-mgr-modules-core=17.2.7-pve3 libradosstriper1=17.2.7-pve3 libsqlite3-mod-ceph=17.2.7-pve3 librados2=17.2.7-pve3 librbd1=17.2.7-pve3 ceph-common=17.2.7-pve3 libcephfs2=17.2.7-pve3 python3-cephfs=17.2.7-pve3 python3-ceph-argparse=17.2.7-pve3 python3-ceph-common=17.2.7-pve3 python3-rados=17.2.7-pve3 python3-rbd=17.2.7-pve3 python3-rgw=17.2.7-pve3 librgw2=17.2.7-pve3 ceph-fuse=17.2.7-pve3 ceph-volume=17.2.7-pve3




Cpeh crash log löschen

Beschreibung:

Wenn ein Doamen crasht bleibt da in der log.
um diese zu lsöchen folgenden Befehl ausführen

Screenshot 2024-09-16 at 17-41-27 backupsrv001 - Proxmox Virtual Environment.png

Befehl:
To display a list of messages:

ceph crash ls

Wenn wir die Nachricht lesen wollen:

ceph crash info <id>

dann:

ceph crash archive <id>

or alle archivieren:

ceph crash archive-all

 

 

 

HDD Tray ermitteln LED blinken und/oder austauschen

Beschreibung:

Es gibt ein tolles Tool. Mit der man die LED zum Tray blinken lassen kann.
Noch ein kleines Script dazu wo man nur dass device angeben muss.Ein weiteres script zum Datenträger tausch.
Lässt slot blinken.
festplatte tauschen
Alte festplatte wird deregistriert und neue hinzugefügt.
LED ausgeschaltet.
BAM

Durchführung:

apt-get install -y lsscsi sg3-utils

Festplatten anzeigen lassen:

lsscsi -g

Ausgabe:

[1:0:0:0]    cd/dvd  Slimtype DVD A  DS8ACSH   LP5M  /dev/sr0   /dev/sg17
[3:0:0:0]    disk    SEAGATE  XS400ME70004     0004  /dev/sda   /dev/sg0 
[3:0:1:0]    disk    SEAGATE  ST20000NM002D    E004  /dev/sdb   /dev/sg1 
[3:0:2:0]    disk    WDC      WUS721010AL5204  C980  /dev/sdc   /dev/sg2 
[3:0:3:0]    disk    SEAGATE  ST20000NM002D    E006  /dev/sdd   /dev/sg3 
[3:0:4:0]    disk    WDC      WUS721010AL5204  C980  /dev/sde   /dev/sg4 
[3:0:5:0]    disk    SEAGATE  ST20000NM002D    E006  /dev/sdf   /dev/sg5 
[3:0:6:0]    disk    WDC      WUS721010AL5204  C980  /dev/sdg   /dev/sg6 
[3:0:7:0]    disk    WDC      WUS721010AL5204  C980  /dev/sdh   /dev/sg7 
[3:0:8:0]    disk    WDC      WUS721010AL5204  C980  /dev/sdi   /dev/sg8 
[3:0:9:0]    disk    WDC      WUS721010AL5204  C980  /dev/sdj   /dev/sg9 
[3:0:10:0]   disk    WDC      WUS721010AL5204  C980  /dev/sdk   /dev/sg10
[3:0:11:0]   disk    SEAGATE  XS400ME70004     0004  /dev/sdl   /dev/sg11
[3:0:12:0]   disk    WDC      WUS721010AL5204  C980  /dev/sdm   /dev/sg12
[3:0:13:0]   disk    WDC      WUS721010AL5204  C980  /dev/sdn   /dev/sg13
[3:0:14:0]   disk    WDC      WUS721010AL5204  C980  /dev/sdo   /dev/sg14
[3:0:15:0]   disk    WDC      WUS721010AL5204  C980  /dev/sdp   /dev/sg15
[3:0:16:0]   enclosu BROADCOM VirtualSES       03    -          /dev/sg16
[4:0:0:0]    cd/dvd  AMI      Virtual CDROM0   1.00  /dev/sr1   /dev/sg18

Script:

nano /usr/local/bin/identify-disk.sh

Inhalt

#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<USAGE
Usage:
  identify-disk [--on|--off|--blink SECONDS] [--symlink|--ses] [--all] [/dev/sdX|sdX|sdXn]

Optionen:
  --on / --off / --blink SECONDS   LED steuern
  --symlink                        nur sysfs/enclosure_device* nutzen
  --ses                            nur SES (sg_ses) nutzen
  --all                            auf alle verfügbaren Slots anwenden
  (ohne Methode)                   auto: erst symlink, dann SES-Fallback

Beispiele:
  identify-disk --on        sdi
  identify-disk --blink 10  sdg8
  identify-disk --off       --symlink sdi
  identify-disk --on        --ses     sdi
  identify-disk --off       --all             # alle LEDs aus
  identify-disk --blink 5   --all --symlink   # alle via sysfs blinken
USAGE
}

MODE="on"
BLINK_SECS=0
METHOD="auto"   # auto | symlink | ses
ALL=0
DISK=""

[[ $# -lt 1 ]] && { usage; exit 1; }

while [[ $# -gt 0 ]]; do
  case "${1:-}" in
    --on) MODE="on"; shift ;;
    --off) MODE="off"; shift ;;
    --blink) MODE="blink"; BLINK_SECS="${2:-}"; [[ -z "$BLINK_SECS" ]] && { echo "Fehlende Sekunden bei --blink"; exit 1; }; shift 2 ;;
    --symlink) METHOD="symlink"; shift ;;
    --ses) METHOD="ses"; shift ;;
    --all) ALL=1; shift ;;
    -h|--help) usage; exit 0 ;;
    *)
      DISK="$1"; shift ;;
  esac
done

# ---------------------------
# Helpers (norm/req/printing)
# ---------------------------
need() { command -v "$1" >/dev/null 2>&1 || { echo "$1 fehlt. Bitte installieren."; exit 1; }; }

normalize_disk() {
  local d="$1"
  [[ "$d" =~ ^sd ]] && d="/dev/$d"
  local base="$(basename "$d")"
  local base_nopart="${base%%[0-9]*}"
  echo "/dev/$base_nopart"
}

# --------------------------------------
# Einzel-Operationen (SYMLINK / per Disk)
# --------------------------------------
do_symlink_one() {
  local disk="$1"
  local base_nopart="$(basename "$disk")"
  local p="/sys/class/block/${base_nopart}/device"
  local enc=( "$p"/enclosure_device* )
  [[ -e "${enc[0]}" ]] || { echo "Kein enclosure_device* für $disk gefunden."; return 2; }
  local LOCATE="${enc[0]}/locate"
  [[ -w "$LOCATE" ]] || { echo "'locate' nicht verfügbar/schreibbar unter ${enc[0]}."; return 3; }
  local slot="$(cat "${enc[0]}/slot" 2>/dev/null || echo "")"
  local slot_lbl=""; [[ -n "$slot" ]] && slot_lbl=" (Slot $slot)"
  case "$MODE" in
    on)    echo 1 | sudo tee "$LOCATE" >/dev/null; echo "ON  via sysfs$slot_lbl – $disk";;
    off)   echo 0 | sudo tee "$LOCATE" >/dev/null; echo "OFF via sysfs$slot_lbl – $disk";;
    blink) echo 1 | sudo tee "$LOCATE" >/dev/null; echo "ON  via sysfs$slot_lbl – $disk"; sleep "$BLINK_SECS"; echo 0 | sudo tee "$LOCATE" >/dev/null; echo "OFF via sysfs$slot_lbl – $disk";;
  esac
}

# --------------------------------------
# Einzel-Operationen (SES / per Disk)
# --------------------------------------
do_ses_one() {
  local disk="$1"
  need lsscsi; need sg_ses
  local LINE
  LINE="$(lsscsi -g | awk -v d="$disk" '{if ($(NF-1)==d) {print; exit}}')"
  [[ -n "$LINE" ]] || { echo "Konnte $disk nicht in 'lsscsi -g' finden."; return 6; }

  local HOST BUS TARGET LUN
  if [[ "$LINE" =~ \[([0-9]+):([0-9]+):([0-9]+):([0-9]+)\] ]]; then
    HOST="${BASH_REMATCH[1]}"; BUS="${BASH_REMATCH[2]}"; TARGET="${BASH_REMATCH[3]}"; LUN="${BASH_REMATCH[4]}"
  else
    echo "Konnte SCSI-Adresse nicht parsen."; return 7
  fi

  local SES_LINE SES_DEV
  SES_LINE="$(lsscsi -g | awk -v h="$HOST" -v b="$BUS" '$2=="enclosu" && $1 ~ ("\\["h":"b":"){print; exit}')"
  [[ -n "$SES_LINE" ]] || { echo "Kein SES/Enclosure auf ${HOST}:${BUS} gefunden (HW-RAID? Hersteller-CLI nötig)."; return 8; }
  SES_DEV="$(echo "$SES_LINE" | awk '{print $NF}')"
  [[ -e "$SES_DEV" ]] || { echo "SES-Gerät existiert nicht: $SES_DEV"; return 9; }

  local SAS_PATH="/sys/class/scsi_device/${HOST}:${BUS}:${TARGET}:${LUN}/device/sas_address"
  [[ -r "$SAS_PATH" ]] || { echo "SAS-Adresse nicht lesbar: $SAS_PATH"; return 10; }
  local DISK_SAS; DISK_SAS="$(tr -d '\n' < "$SAS_PATH")"
  [[ -n "$DISK_SAS" ]] || { echo "Leere SAS-Adresse."; return 11; }

  local INDEX SLOTNUM
  read INDEX SLOTNUM < <(sg_ses -p aes "$SES_DEV" 2>/dev/null \
    | awk -v want="$DISK_SAS" '
        /Element index:/              {idx=$3; gsub(":","",idx); slot=""}
        /device slot number:/         {slot=$5}
        /SAS address:/ && $3 ~ /^0x/  {sas=$3; if (tolower(sas)==tolower(want)) {print idx, slot; exit}}
      ')
  [[ -n "${INDEX:-}" ]] || { echo "Konnte SES-Index für $disk nicht ermitteln."; return 12; }

  local slot_lbl=""; [[ -n "${SLOTNUM:-}" ]] && slot_lbl=" (Slot $SLOTNUM, idx $INDEX)" || slot_lbl=" (idx $INDEX)"
  case "$MODE" in
    on)    sg_ses --index="$INDEX" --set=ident "$SES_DEV"; echo "ON  via SES$slot_lbl – $disk";;
    off)   sg_ses --index="$INDEX" --clear=ident "$SES_DEV"; echo "OFF via SES$slot_lbl – $disk";;
    blink) sg_ses --index="$INDEX" --set=ident "$SES_DEV"; echo "ON  via SES$slot_lbl – $disk"; sleep "$BLINK_SECS"; sg_ses --index="$INDEX" --clear=ident "$SES_DEV"; echo "OFF via SES$slot_lbl – $disk";;
  esac
}

# --------------------------------------
# ALL-Operationen (SYMLINK)
# --------------------------------------
do_symlink_all() {
  local disks=()
  for d in /sys/class/block/sd*; do
    [[ -e "$d" ]] || continue
    local name="$(basename "$d")"
    [[ "$name" =~ [0-9]$ ]] && continue   # nur Whole Disks
    comp=( "$d"/device/enclosure_device* )
    [[ -e "${comp[0]}" ]] || continue
    disks+=( "/dev/$name" )
  done
  local n="${#disks[@]}"
  [[ $n -gt 0 ]] || { echo "Keine sysfs/enclosure Slots gefunden."; return 2; }

  if [[ "$MODE" == "blink" ]]; then
    # Alle an, warten, alle aus
    for disk in "${disks[@]}"; do
      local loc=( "/sys/class/block/$(basename "$disk")/device"/enclosure_device*/locate )
      [[ -w "${loc[0]}" ]] || continue
      echo 1 | sudo tee "${loc[0]}" >/dev/null
      local slot=""; [[ -r "${loc[0]%/*}/slot" ]] && slot="$(cat "${loc[0]%/*}/slot")"
      echo "ON  via sysfs$( [[ -n "$slot" ]] && echo " (Slot $slot)" ) – $disk"
    done
    sleep "$BLINK_SECS"
    for disk in "${disks[@]}"; do
      local loc=( "/sys/class/block/$(basename "$disk")/device"/enclosure_device*/locate )
      [[ -w "${loc[0]}" ]] || continue
      echo 0 | sudo tee "${loc[0]}" >/dev/null
      echo "OFF via sysfs – $disk"
    done
  else
    local val=$([[ "$MODE" == "on" ]] && echo 1 || echo 0)
    for disk in "${disks[@]}"; do
      local loc=( "/sys/class/block/$(basename "$disk")/device"/enclosure_device*/locate )
      [[ -w "${loc[0]}" ]] || continue
      echo $val | sudo tee "${loc[0]}" >/dev/null
      local slot=""; [[ -r "${loc[0]%/*}/slot" ]] && slot="$(cat "${loc[0]%/*}/slot")"
      echo "$( [[ $val -eq 1 ]] && echo ON || echo OFF ) via sysfs$( [[ -n "$slot" ]] && echo " (Slot $slot)" ) – $disk"
    done
  fi
}

# --------------------------------------
# ALL-Operationen (SES)
# --------------------------------------
do_ses_all() {
  need lsscsi; need sg_ses
  mapfile -t ENCS < <(lsscsi -g | awk '$2=="enclosu"{print $NF}')
  [[ ${#ENCS[@]} -gt 0 ]] || { echo "Kein SES/Enclosure gefunden."; return 3; }

  for SES_DEV in "${ENCS[@]}"; do
    # Alle belegten Element-Indices sammeln (die eine SAS address haben)
    mapfile -t IDX < <(sg_ses -p aes "$SES_DEV" 2>/dev/null \
      | awk '
          /Element index:/ {idx=$3; gsub(":","",idx); slot=""; has_sas=0}
          /device slot number:/ {slot=$5}
          /SAS address:/ && $3 ~ /^0x/ {has_sas=1}
          has_sas && /SAS address:/ {print idx "|" slot}
        ')
    [[ ${#IDX[@]} -gt 0 ]] || { echo "Keine befüllten Slots für $SES_DEV."; continue; }

    if [[ "$MODE" == "blink" ]]; then
      # alle an
      for pair in "${IDX[@]}"; do
        IFS='|' read -r index slot <<<"$pair"
        sg_ses --index="$index" --set=ident "$SES_DEV" || true
        [[ -n "$slot" ]] && echo "ON  via SES (Slot $slot, idx $index) – $SES_DEV" || echo "ON  via SES (idx $index) – $SES_DEV"
      done
      sleep "$BLINK_SECS"
      # alle aus
      for pair in "${IDX[@]}"; do
        IFS='|' read -r index slot <<<"$pair"
        sg_ses --index="$index" --clear=ident "$SES_DEV" || true
        [[ -n "$slot" ]] && echo "OFF via SES (Slot $slot, idx $index) – $SES_DEV" || echo "OFF via SES (idx $index) – $SES_DEV"
      done
    else
      local cmd=$([[ "$MODE" == "on" ]] && echo "--set=ident" || echo "--clear=ident")
      for pair in "${IDX[@]}"; do
        IFS='|' read -r index slot <<<"$pair"
        sg_ses --index="$index" $cmd "$SES_DEV" || true
        local state=$([[ "$MODE" == "on" ]] && echo ON || echo OFF)
        [[ -n "$slot" ]] && echo "$state via SES (Slot $slot, idx $index) – $SES_DEV" || echo "$state via SES (idx $index) – $SES_DEV"
      done
    fi
  done
}

# -----------------------
# Main-Dispatch
# -----------------------
if [[ $ALL -eq 1 ]]; then
  case "$METHOD" in
    symlink)
      do_symlink_all
      ;;
    ses)
      do_ses_all
      ;;
    auto)
      # erst symlink-Variante probieren; wenn nichts gefunden, SES-all
      if ! do_symlink_all; then
        echo "(Auto) Fallback auf SES (alle)…"
        do_ses_all
      fi
      ;;
    *) echo "Unbekannte Methode: $METHOD"; usage; exit 1 ;;
  esac
  exit 0
fi

# Einzel-Disk-Pfad (keine --all)
[[ -n "$DISK" ]] || { echo "Bitte /dev/sdX angeben oder --all nutzen."; exit 1; }
DISK="$(normalize_disk "$DISK")"
[[ -b "$DISK" ]] || { echo "Gerät nicht gefunden: $DISK"; exit 1; }

case "$METHOD" in
  symlink)
    do_symlink_one "$DISK" || exit $?
    ;;
  ses)
    do_ses_one "$DISK" || exit $?
    ;;
  auto)
    if do_symlink_one "$DISK"; then
      exit 0
    else
      echo "(Auto) Fallback auf SES…"
      do_ses_one "$DISK"
    fi
    ;;
  *)
    echo "Unbekannte Methode: $METHOD"; usage; exit 1 ;;
esac

Ausführbar machen

chmod +x /usr/local/bin/identify-disk.sh

Hilfe/Bedienung

Usage:
  identify-disk [--on|--off|--blink SECONDS] [--symlink|--ses] [--all] [/dev/sdX|sdX|sdXn]

Optionen:
  --on / --off / --blink SECONDS   LED steuern
  --symlink                        nur sysfs/enclosure_device* nutzen
  --ses                            nur SES (sg_ses) nutzen
  --all                            auf alle verfügbaren Slots anwenden
  (ohne Methode)                   auto: erst symlink, dann SES-Fallback

Beispiele:
  identify-disk --on        sdi
  identify-disk --blink 10  sdg8
  identify-disk --off       --symlink sdi
  identify-disk --on        --ses     sdi
  identify-disk --off       --all             # alle LEDs aus
  identify-disk --blink 5   --all --symlink   # alle via sysfs blinken

Alte Laufwerke entfernen:

Sobald alte Laufwerke entfernt werden, bleiben Sie tot in der Liste.
Erst Laufwerk entfernen. Dann neu einschieben.
Das machen wir wieder mit einem script. Das Script wartet solange bis wir die festplatte getauscht haben.
wenn getauscht bestätigen.

nano /usr/local/bin/scsi-hotswap.sh

Inhalt

#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<USAGE
Usage:
  scsi-hotswap [--method auto|symlink|ses] [--blink N|--no-led] [--no-prompt] /dev/sdX|sdX|sdXn

Optionen:
  --method M     M = auto (default) | symlink | ses
  --blink N      LED vor dem Tausch N Sekunden blinken (statt dauerhaft an)
  --no-led       keine LED-Steuerung
  --no-prompt    nicht auf ENTER warten (setze voraus, dass neue Platte schon steckt)

Beispiele:
  scsi-hotswap sdi
  scsi-hotswap --method symlink --blink 8 sdg8
  scsi-hotswap --method ses --no-prompt sdm
USAGE
}

METHOD="auto"      # auto | symlink | ses
BLINK_SECS=0       # 0 = steady on
USE_LED=1
PROMPT=1

[[ $# -lt 1 ]] && { usage; exit 1; }
while [[ $# -gt 0 ]]; do
  case "${1:-}" in
    --method) METHOD="${2:-}"; shift 2 ;;
    --blink)  BLINK_SECS="${2:-}"; [[ -z "$BLINK_SECS" ]] && { echo "Fehlende Sekunden bei --blink"; exit 1; }; shift 2 ;;
    --no-led) USE_LED=0; shift ;;
    --no-prompt) PROMPT=0; shift ;;
    -h|--help) usage; exit 0 ;;
    *) DISK="$1"; shift ;;
  esac
done

# --- Device normalisieren ---
[[ "$DISK" =~ ^sd ]] && DISK="/dev/$DISK"
BASE="$(basename "$DISK")"
BASE_NOPART="${BASE%%[0-9]*}"
DISK="/dev/$BASE_NOPART"
[[ -b "$DISK" ]] || { echo "Gerät nicht gefunden: $DISK"; exit 1; }

need() { command -v "$1" >/dev/null 2>&1 || { echo "$1 fehlt. Bitte installieren."; exit 1; }; }

# --------------------------
# LED via sysfs (symlink-Weg)
# --------------------------
# merkt sich LOCATE_PATH_CACHED+SLOT_CACHED, damit "off" nach dem Swap immer klappt
LOCATE_PATH_CACHED=""
SLOT_CACHED=""

led_symlink() {
  local mode="$1"  # on|off|blink
  local LOCATE_PATH=""
  local SLOT=""

  # bereits gecachten Pfad benutzen, wenn vorhanden
  if [[ -n "$LOCATE_PATH_CACHED" && -e "$LOCATE_PATH_CACHED" ]]; then
    LOCATE_PATH="$LOCATE_PATH_CACHED"
    SLOT="$SLOT_CACHED"
  else
    local p="/sys/class/block/${BASE_NOPART}/device"
    local enc=( "$p"/enclosure_device* )
    [[ -e "${enc[0]}" ]] || return 2
    LOCATE_PATH="${enc[0]}/locate"
    [[ -w "$LOCATE_PATH" ]] || return 3
    SLOT="$(cat "${enc[0]}/slot" 2>/dev/null || echo "")"
    LOCATE_PATH_CACHED="$LOCATE_PATH"
    SLOT_CACHED="$SLOT"
  fi

  local slot_label=""
  [[ -n "$SLOT" ]] && slot_label=" (Slot $SLOT)"

  case "$mode" in
    on)
      echo 1 | sudo tee "$LOCATE_PATH" >/dev/null
      echo "LED an${slot_label} via sysfs – $DISK"
      ;;
    off)
      echo 0 | sudo tee "$LOCATE_PATH" >/dev/null
      echo "LED aus${slot_label} via sysfs – $DISK"
      ;;
    blink)
      echo 1 | sudo tee "$LOCATE_PATH" >/dev/null
      echo "LED an${slot_label} – blinke ${BLINK_SECS}s…"
      sleep "$BLINK_SECS"
      echo 0 | sudo tee "$LOCATE_PATH" >/dev/null
      echo "LED aus."
      ;;
  esac
  return 0
}

# -------------------------------------------
# SES-Index + Slotnummer + SES-Device ermitteln (per SAS)
# -------------------------------------------
get_ses_index() {
  # Outputs (echo): "<SES_DEV> <INDEX> <SLOTNUM> <HOST> <BUS> <TARGET> <LUN>"
  need lsscsi; need sg_ses

  local LINE
  LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
  [[ -n "$LINE" ]] || { echo "Konnte $DISK nicht in 'lsscsi -g' finden." >&2; return 1; }

  if [[ "$LINE" =~ \[([0-9]+):([0-9]+):([0-9]+):([0-9]+)\] ]]; then
    local HOST="${BASH_REMATCH[1]}" BUS="${BASH_REMATCH[2]}" TARGET="${BASH_REMATCH[3]}" LUN="${BASH_REMATCH[4]}"
  else
    echo "Konnte SCSI-Adresse nicht parsen." >&2; return 1
  fi

  local SES_LINE SES_DEV
  SES_LINE="$(lsscsi -g | awk -v h="$HOST" -v b="$BUS" '$2=="enclosu" && $1 ~ ("\\["h":"b":"){print; exit}')"
  [[ -n "$SES_LINE" ]] || { echo "Kein SES/Enclosure auf ${HOST}:${BUS} gefunden (HW-RAID?)." >&2; return 1; }
  SES_DEV="$(echo "$SES_LINE" | awk '{print $NF}')"
  [[ -e "$SES_DEV" ]] || { echo "SES-Gerät existiert nicht: $SES_DEV" >&2; return 1; }

  local SAS_PATH="/sys/class/scsi_device/${HOST}:${BUS}:${TARGET}:${LUN}/device/sas_address"
  [[ -r "$SAS_PATH" ]] || { echo "SAS-Adresse nicht lesbar: $SAS_PATH" >&2; return 1; }
  local DISK_SAS; DISK_SAS="$(tr -d '\n' < "$SAS_PATH")"
  [[ -n "$DISK_SAS" ]] || { echo "Leere SAS-Adresse." >&2; return 1; }

  # In einem Durchlauf: Index + physische Slotnummer zu *dieser* Disk finden
  local INDEX SLOTNUM
  read INDEX SLOTNUM < <(sg_ses -p aes "$SES_DEV" 2>/dev/null \
    | awk -v want="$DISK_SAS" '
        /Element index:/              {idx=$3; gsub(":","",idx); slot=""}
        /device slot number:/         {slot=$5}
        /SAS address:/ && $3 ~ /^0x/  {sas=$3; if (tolower(sas)==tolower(want)) {print idx, slot; exit}}
      ')

  # Fallback über physische Slotnummer aus sysfs (falls vorhanden)
  if [[ -z "${INDEX:-}" || -z "${SLOTNUM:-}" ]]; then
    local p="/sys/class/block/${BASE_NOPART}/device"
    local enc=( "$p"/enclosure_device* )
    if [[ -e "${enc[0]}" && -r "${enc[0]}/slot" ]]; then
      local PHY_SLOT; PHY_SLOT="$(cat "${enc[0]}/slot" 2>/dev/null || true)"
      if [[ -n "$PHY_SLOT" ]]; then
        SLOTNUM="$PHY_SLOT"
        INDEX="$(sg_ses -p aes "$SES_DEV" 2>/dev/null \
          | awk -v slot="$PHY_SLOT" '
              /Element index:/ {idx=$3; gsub(":","",idx)}
              /device slot number:/ {if ($5==slot) {print idx; exit}}
            ')"
      fi
    fi
  fi

  # Es kann vorkommen, dass SLOTNUM leer bleibt → ist ok; dann nur Index nutzen
  [[ -n "$INDEX" ]] || { echo "SES-Index konnte nicht ermittelt werden." >&2; return 1; }
  echo "$SES_DEV" "$INDEX" "${SLOTNUM:-}" "$HOST" "$BUS" "$TARGET" "$LUN"
}

# -----------------------
# LED via SES (sg_ses)
# -----------------------
led_ses() {
  local mode="$1" SES_DEV="$2" INDEX="$3" SLOTNUM="${4:-}"
  need sg_ses
  local slot_label=""
  [[ -n "$SLOTNUM" ]] && slot_label=" (Slot $SLOTNUM)"
  case "$mode" in
    on)
      sg_ses --index="$INDEX" --set=ident "$SES_DEV"
      echo "LED an${slot_label}, SES index $INDEX via $SES_DEV – $DISK"
      ;;
    off)
      sg_ses --index="$INDEX" --clear=ident "$SES_DEV"
      echo "LED aus${slot_label}, SES index $INDEX via $SES_DEV – $DISK"
      ;;
    blink)
      sg_ses --index="$INDEX" --set=ident "$SES_DEV"
      echo "LED an${slot_label} – blinke ${BLINK_SECS}s (SES index $INDEX)…"
      sleep "$BLINK_SECS"
      sg_ses --index="$INDEX" --clear=ident "$SES_DEV"
      echo "LED aus."
      ;;
  esac
}

# ---------------------------------------------
# Methode wählen & LED einschalten (falls gew.)
# ---------------------------------------------
SES_DEV=""; INDEX=""; SLOTNUM=""; HOST=""; BUS=""; TARGET=""; LUN=""
OLDDEV=""

if (( USE_LED )); then
  case "$METHOD" in
    symlink)
      led_symlink "$([[ $BLINK_SECS -gt 0 ]] && echo blink || echo on)" \
        || { echo "Symlink-LED nicht verfügbar."; exit 1; }
      # H:B:T:L & OLDDEV für delete/scan:
      need lsscsi
      LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
      [[ -n "$LINE" ]] || { echo "Konnte $DISK nicht in 'lsscsi -g' finden."; exit 1; }
      OLDDEV="$(awk '{print $(NF-1)}' <<<"$LINE")"
      if [[ "$LINE" =~ \[([0-9]+):([0-9]+):([0-9]+):([0-9]+)\] ]]; then
        HOST="${BASH_REMATCH[1]}"; BUS="${BASH_REMATCH[2]}"; TARGET="${BASH_REMATCH[3]}"; LUN="${BASH_REMATCH[4]}"
      else
        echo "Konnte SCSI-Adresse nicht parsen."; exit 1
      fi
      ;;
    ses)
      read SES_DEV INDEX SLOTNUM HOST BUS TARGET LUN < <(get_ses_index) || exit 1
      led_ses "$([[ $BLINK_SECS -gt 0 ]] && echo blink || echo on)" "$SES_DEV" "$INDEX" "$SLOTNUM"
      # OLDDEV zusätzlich erfassen (nur Info)
      need lsscsi
      LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
      [[ -n "$LINE" ]] && OLDDEV="$(awk '{print $(NF-1)}' <<<"$LINE")" || true
      ;;
    auto)
      if ! led_symlink "$([[ $BLINK_SECS -gt 0 ]] && echo blink || echo on)"; then
        echo "(Auto) Fallback auf SES…"
        read SES_DEV INDEX SLOTNUM HOST BUS TARGET LUN < <(get_ses_index) || exit 1
        led_ses "$([[ $BLINK_SECS -gt 0 ]] && echo blink || echo on)" "$SES_DEV" "$INDEX" "$SLOTNUM"
      else
        # Symlink-Weg erfolgreich: H:B:T:L & OLDDEV besorgen
        need lsscsi
        LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
        [[ -n "$LINE" ]] || { echo "Konnte $DISK nicht in 'lsscsi -g' finden."; exit 1; }
        OLDDEV="$(awk '{print $(NF-1)}' <<<"$LINE")"
        if [[ "$LINE" =~ \[([0-9]+):([0-9]+):([0-9]+):([0-9]+)\] ]]; then
          HOST="${BASH_REMATCH[1]}"; BUS="${BASH_REMATCH[2]}"; TARGET="${BASH_REMATCH[3]}"; LUN="${BASH_REMATCH[4]}"
        else
          echo "Konnte SCSI-Adresse nicht parsen."; exit 1
        fi
      fi
      ;;
    *) echo "Unbekannte Methode: $METHOD"; exit 1 ;;
  esac
else
  # Keine LED: wir brauchen nur H:B:T:L & OLDDEV
  need lsscsi
  LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
  [[ -n "$LINE" ]] || { echo "Konnte $DISK nicht in 'lsscsi -g' finden."; exit 1; }
  OLDDEV="$(awk '{print $(NF-1)}' <<<"$LINE")"
  if [[ "$LINE" =~ \[([0-9]+):([0-9]+):([0-9]+):([0-9]+)\] ]]; then
    HOST="${BASH_REMATCH[1]}"; BUS="${BASH_REMATCH[2]}"; TARGET="${BASH_REMATCH[3]}"; LUN="${BASH_REMATCH[4]}"
  else
    echo "Konnte SCSI-Adresse nicht parsen."; exit 1
  fi
fi

# -------------
# Deregister
# -------------
echo ">>> Entferne $DISK (SCSI ${HOST}:${BUS}:${TARGET}:${LUN})"
echo 1 | sudo tee "/sys/class/scsi_device/${HOST}:${BUS}:${TARGET}:${LUN}/device/delete" >/dev/null || true

# -------------
# Prompt / Swap (ohne Slotnummer)
# -------------
if (( PROMPT )); then
  read -p ">>> Bitte neue Festplatte einsetzen und ENTER drücken… " _
fi

# -------------
# Rescan (gezielt für den Target-Slot)
# -------------
echo ">>> Rescanne Slot (Target ${TARGET}) über host${HOST}…"
echo "${HOST} ${BUS} ${TARGET}" | sudo tee "/sys/class/scsi_host/host${HOST}/scan" >/dev/null

# -------------
# Neues Device finden (by H:B:T:L)
# -------------
echo ">>> Warte auf neues Blockdevice im Slot (Target ${TARGET})…"
need lsscsi
NEWDISK=""
for i in {1..20}; do
  NEWLINE="$(lsscsi -g | awk -v h="$HOST" -v b="$BUS" -v t="$TARGET" '$1==sprintf("[%d:%d:%d:0]",h,b,t){print; exit}')"
  if [[ -n "$NEWLINE" ]]; then
    NEWDISK="$(awk '{print $(NF-1)}' <<<"$NEWLINE")"
    echo ">>> Neues Device: $NEWDISK  ($NEWLINE)"
    break
  fi
  sleep 1
done
if [[ -n "$NEWDISK" ]]; then
  if [[ -n "$OLDDEV" ]]; then
    if [[ "$NEWDISK" == "$OLDDEV" ]]; then
      echo ">>> Hinweis: Laufwerksbuchstabe unverändert geblieben ($NEWDISK) – alles ok."
    else
      echo ">>> Hinweis: Buchstabe wechselte: alt=$OLDDEV neu=$NEWDISK (normal bei Hot-Swap)."
    fi
  fi
else
  echo "Hinweis: Im Zeitfenster kein neues Device sichtbar. Entweder Treiber/Controller langsam, oder der Slot wurde noch nicht neu gemeldet. Prüfe lsscsi/Logs."
fi

# -------------
# LED aus
# -------------
if (( USE_LED )); then
  case "$METHOD" in
    symlink)
      led_symlink off || true           # nutzt den gecachten locate-Pfad
      ;;
    ses)
      led_ses off "$SES_DEV" "$INDEX" "$SLOTNUM" || true
      ;;
    auto)
      if [[ -n "${SES_DEV:-}" && -n "${INDEX:-}" ]]; then
        led_ses off "$SES_DEV" "$INDEX" "$SLOTNUM" || true
      else
        led_symlink off || true
      fi
      ;;
  esac
fi

echo ">>> Fertig."

Nun noch ausführbar machen

chmod +x /usr/local/bin/scsi-hotswap.sh

Hilfe/Benutzung:

Usage:
  scsi-hotswap [--method auto|symlink|ses] [--blink N|--no-led] [--no-prompt] /dev/sdX|sdX|sdXn

Optionen:
  --method M     M = auto (default) | symlink | ses
  --blink N      LED vor dem Tausch N Sekunden blinken (statt dauerhaft an)
  --no-led       keine LED-Steuerung
  --no-prompt    nicht auf ENTER warten (setze voraus, dass neue Platte schon steckt)

Beispiele:
  scsi-hotswap sdi
  scsi-hotswap --method symlink --blink 8 sdg8
  scsi-hotswap --method ses --no-prompt sdm

Ausgabe:

root@backupsrv001:~# scsi-hotswap.sh /dev/sdq
>>> Entferne /dev/sdq (SCSI 3:0:17:0)
>>> Bitte neue Festplatte in Slot 17 einsetzen...
Weiter mit ENTER, wenn neue Platte steckt.
>>> Rescanne Slot 17...
>>> Neue Device-Liste: