++ Primo Caricamento
This commit is contained in:
172
README.md
Normal file
172
README.md
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# LVM Disk Auto Add
|
||||||
|
|
||||||
|
Script Bash per rilevare automaticamente un nuovo disco vuoto, aggiungerlo a LVM e aumentare il filesystem di root (`/`).
|
||||||
|
|
||||||
|
> ⚠️ **Attenzione:** questo script modifica in modo distruttivo la configurazione storage (inizializza il disco con `pvcreate`). Usalo solo se sai esattamente cosa stai facendo.
|
||||||
|
|
||||||
|
## Cosa fa
|
||||||
|
|
||||||
|
Lo script `auto-lvm-add-disk.sh` esegue questa sequenza:
|
||||||
|
|
||||||
|
1. Verifica che l’utente sia `root`.
|
||||||
|
1. Acquisisce un lock file (`flock`) per evitare esecuzioni concorrenti.
|
||||||
|
1. Salva lo spazio iniziale del filesystem `/`.
|
||||||
|
1. Forza una scansione SCSI su tutti gli host (`/sys/class/scsi_host/host*/scan`).
|
||||||
|
1. Se passato `--disk`, usa il disco specificato (con validazioni); altrimenti cerca il primo disco di tipo `disk`, senza filesystem (`FSTYPE` vuoto) e senza partizioni.
|
||||||
|
1. Inizializza il disco come Physical Volume (`pvcreate`).
|
||||||
|
1. Determina il device del mountpoint `/`, il relativo LV e il VG associato.
|
||||||
|
1. Estende il Volume Group (`vgextend`).
|
||||||
|
1. Estende il Logical Volume al 100% dello spazio libero (`lvextend -l +100%FREE`).
|
||||||
|
1. Esegue il resize del filesystem in base al tipo (`ext2/ext3/ext4` → `resize2fs`, `xfs` → `xfs_growfs /`).
|
||||||
|
1. Mostra un riepilogo finale e scrive il log in `extend-lvm.log`.
|
||||||
|
|
||||||
|
## Requisiti
|
||||||
|
|
||||||
|
- Linux con LVM già configurato.
|
||||||
|
- Filesystem root supportato: `ext2`, `ext3`, `ext4`, `xfs`.
|
||||||
|
- Accesso root.
|
||||||
|
- Utility richieste: `lsblk`, `df`, `awk`, `grep`, `findmnt`, `lvs`, `pvcreate`, `vgextend`, `lvextend`, `flock`.
|
||||||
|
- Utility resize: `resize2fs` (per `ext*`) **oppure** `xfs_growfs` (per `xfs`).
|
||||||
|
|
||||||
|
## Limitazioni importanti
|
||||||
|
|
||||||
|
Lo script assume implicitamente che:
|
||||||
|
|
||||||
|
- il mountpoint `/` sia su un Logical Volume LVM;
|
||||||
|
- il disco da aggiungere sia chiaramente identificabile come “nuovo e vuoto”;
|
||||||
|
- il filesystem root sia tra quelli supportati (`ext*` o `xfs`).
|
||||||
|
|
||||||
|
In ambienti con più VG/LV o dischi multipli non inizializzati, è necessario verificare attentamente il comportamento prima dell’uso in produzione.
|
||||||
|
|
||||||
|
## Audit rapido dello script (stato attuale)
|
||||||
|
|
||||||
|
Esito: **script migliorato** con hardening sui punti più critici.
|
||||||
|
|
||||||
|
### Priorità alta
|
||||||
|
|
||||||
|
- ✅ **Selezione target VG/LV più sicura**: ora usa il device del mountpoint `/` e ricava il VG con `lvs`.
|
||||||
|
- ✅ **Rilevamento disco più robusto**: supporta `--disk` per scelta esplicita del device target.
|
||||||
|
- ✅ **Compatibilità filesystem**: supporto `ext*` e `xfs` con comando dedicato.
|
||||||
|
|
||||||
|
### Priorità media
|
||||||
|
|
||||||
|
- ✅ **Verifica dipendenze all’avvio**: controllo esplicito dei comandi richiesti.
|
||||||
|
- ✅ **Lock anti-esecuzione concorrente**: esecuzione esclusiva con `flock`.
|
||||||
|
- ✅ **Migliore robustezza shell**: aggiunto `set -o pipefail`.
|
||||||
|
|
||||||
|
### Priorità bassa
|
||||||
|
|
||||||
|
- **Parametrizzazione avanzata**: opzioni CLI per specificare VG/LV e mountpoint (oltre a `--disk` già presente).
|
||||||
|
- **Conferma interattiva in LIVE** (con bypass `--yes`) per ridurre errori operativi.
|
||||||
|
- **Log path assoluto** (es. `/var/log/extend-lvm.log`) per evitare dipendenza dalla directory corrente.
|
||||||
|
|
||||||
|
## Roadmap minima consigliata
|
||||||
|
|
||||||
|
1. Introdurre parametri opzionali `--vg`, `--lv`.
|
||||||
|
2. Migliorare validazioni pre-flight (es. conferma interattiva opzionale in live).
|
||||||
|
3. Consentire lock path configurabile via variabile/env.
|
||||||
|
4. Aggiungere validazioni extra su dischi multipath/LUN complesse.
|
||||||
|
5. Mantenere `test` come default operativo in ambienti sensibili.
|
||||||
|
|
||||||
|
## Utilizzo
|
||||||
|
|
||||||
|
### 1) Dare permessi di esecuzione
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x auto-lvm-add-disk.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2) Eseguire in modalità test (dry-run)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./auto-lvm-add-disk.sh test
|
||||||
|
```
|
||||||
|
|
||||||
|
In questa modalità i comandi vengono solo loggati (`[TEST]`) e **non eseguiti**.
|
||||||
|
|
||||||
|
### 2-bis) Specificare il disco esplicitamente (consigliato in produzione)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./auto-lvm-add-disk.sh --disk /dev/sdb
|
||||||
|
```
|
||||||
|
|
||||||
|
Oppure:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./auto-lvm-add-disk.sh test --disk=sdb
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3) Eseguire in modalità live
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./auto-lvm-add-disk.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
In modalità live i comandi vengono eseguiti (`[RUN]`).
|
||||||
|
|
||||||
|
## Log
|
||||||
|
|
||||||
|
Il log viene scritto nel file:
|
||||||
|
|
||||||
|
- `extend-lvm.log`
|
||||||
|
|
||||||
|
Ogni riga include timestamp e stato (`[TEST]`, `[RUN]`, messaggi info/errore).
|
||||||
|
|
||||||
|
## Esempio flusso operativo consigliato
|
||||||
|
|
||||||
|
1. Collega/aggiungi il nuovo disco alla VM/server.
|
||||||
|
2. Esegui prima il test:
|
||||||
|
- `sudo ./auto-lvm-add-disk.sh test`
|
||||||
|
3. Verifica nel log che il disco selezionato sia quello atteso.
|
||||||
|
4. Esegui in live:
|
||||||
|
- `sudo ./auto-lvm-add-disk.sh`
|
||||||
|
5. Controlla output finale e spazio disponibile con:
|
||||||
|
- `df -h /`
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### `ERRORE: eseguire come root`
|
||||||
|
|
||||||
|
Esegui lo script con `sudo` o come utente root.
|
||||||
|
|
||||||
|
### `ERRORE: nessun disco nuovo trovato`
|
||||||
|
|
||||||
|
Possibili cause:
|
||||||
|
|
||||||
|
- il disco non è visibile al sistema (controlla `lsblk`),
|
||||||
|
- non è vuoto,
|
||||||
|
- contiene partizioni,
|
||||||
|
- non è stato completato il rescan lato hypervisor/controller.
|
||||||
|
|
||||||
|
### `ERRORE: il device root (...) non risulta un Logical Volume LVM`
|
||||||
|
|
||||||
|
Il mountpoint `/` non è su LVM oppure il mapping device non è leggibile tramite `lvs`.
|
||||||
|
|
||||||
|
### `ERRORE: filesystem root non supportato`
|
||||||
|
|
||||||
|
Il filesystem su `/` non è tra `ext2/ext3/ext4/xfs`.
|
||||||
|
|
||||||
|
### `ERRORE: comando richiesto non trovato`
|
||||||
|
|
||||||
|
Installa il pacchetto che contiene il comando mancante (tool LVM, util-linux o e2fsprogs/xfsprogs a seconda del filesystem).
|
||||||
|
|
||||||
|
### `ERRORE: script già in esecuzione (lock: ...)`
|
||||||
|
|
||||||
|
È già presente un'altra esecuzione attiva. Attendi la fine del processo precedente o verifica lock stale.
|
||||||
|
|
||||||
|
## Sicurezza operativa
|
||||||
|
|
||||||
|
- Testare sempre prima in ambiente di staging.
|
||||||
|
- Effettuare backup/snapshot prima dell’esecuzione live.
|
||||||
|
- Evitare esecuzione concorrente dello script.
|
||||||
|
- Verificare manualmente disco target in ambienti critici.
|
||||||
|
|
||||||
|
## Exit code
|
||||||
|
|
||||||
|
- `0`: esecuzione completata.
|
||||||
|
- `1`: errore (es. non root, nessun disco trovato, o comando fallito).
|
||||||
|
|
||||||
|
## File del progetto
|
||||||
|
|
||||||
|
- `auto-lvm-add-disk.sh` – script principale.
|
||||||
|
- `README.md` – documentazione.
|
||||||
222
auto-lvm-add-disk.sh
Normal file
222
auto-lvm-add-disk.sh
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
LOGFILE="extend-lvm.log"
|
||||||
|
MODE="LIVE"
|
||||||
|
USER_DISK=""
|
||||||
|
|
||||||
|
GREEN="\e[32m"
|
||||||
|
RESET="\e[0m"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Uso: $0 [test|--test] [--disk <device>|--disk=<device>]"
|
||||||
|
echo "Esempi:"
|
||||||
|
echo " $0 test"
|
||||||
|
echo " $0 --disk /dev/sdb"
|
||||||
|
echo " $0 --test --disk=sdb"
|
||||||
|
}
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
test|--test)
|
||||||
|
MODE="TEST"
|
||||||
|
;;
|
||||||
|
--disk)
|
||||||
|
shift
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "ERRORE: --disk richiede un valore" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
USER_DISK="$1"
|
||||||
|
;;
|
||||||
|
--disk=*)
|
||||||
|
USER_DISK="${1#*=}"
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "ERRORE: argomento non riconosciuto: $1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "$(date '+%F %T') | $1" | tee -a "$LOGFILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
if [ "$MODE" == "TEST" ]; then
|
||||||
|
log "[TEST] $*"
|
||||||
|
else
|
||||||
|
log "[RUN] $*"
|
||||||
|
eval "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
log "=========================================="
|
||||||
|
log "Avvio script LVM Auto Expand ($MODE)"
|
||||||
|
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
log "ERRORE: eseguire come root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for cmd in lsblk df awk grep findmnt lvs pvcreate vgextend lvextend flock tr; do
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
log "ERRORE: comando richiesto non trovato: $cmd"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
LOCKFILE="/var/lock/auto-lvm-add-disk.lock"
|
||||||
|
if [ ! -d "/var/lock" ]; then
|
||||||
|
LOCKFILE="/tmp/auto-lvm-add-disk.lock"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec 200>"$LOCKFILE"
|
||||||
|
if ! flock -n 200; then
|
||||||
|
log "ERRORE: script già in esecuzione (lock: $LOCKFILE)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log "Lock acquisito: $LOCKFILE"
|
||||||
|
|
||||||
|
# --- Spazio iniziale ---
|
||||||
|
START_SIZE=$(df -BG / | awk 'NR==2 {print $2}' | tr -d 'G')
|
||||||
|
|
||||||
|
# --- Forza rescan SCSI ---
|
||||||
|
log "Scansione bus SCSI..."
|
||||||
|
for host in /sys/class/scsi_host/host*; do
|
||||||
|
run "echo '- - -' > $host/scan"
|
||||||
|
done
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# --- Trova disco nuovo ---
|
||||||
|
log "Rilevo il nuovo disco..."
|
||||||
|
DISK=""
|
||||||
|
|
||||||
|
if [ -n "$USER_DISK" ]; then
|
||||||
|
if [[ "$USER_DISK" == /dev/* ]]; then
|
||||||
|
DISK="$USER_DISK"
|
||||||
|
else
|
||||||
|
DISK="/dev/$USER_DISK"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -b "$DISK" ]; then
|
||||||
|
log "ERRORE: disco specificato non valido: $DISK"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DISK_TYPE=$(lsblk -ndo TYPE "$DISK")
|
||||||
|
DISK_FSTYPE=$(lsblk -ndo FSTYPE "$DISK")
|
||||||
|
|
||||||
|
if [ "$DISK_TYPE" != "disk" ]; then
|
||||||
|
log "ERRORE: il device specificato non è un disco: $DISK"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$DISK_FSTYPE" ]; then
|
||||||
|
log "ERRORE: il disco specificato contiene già un filesystem: $DISK"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if lsblk "$DISK" | grep -q part; then
|
||||||
|
log "ERRORE: il disco specificato contiene partizioni: $DISK"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Disco specificato da CLI: $DISK"
|
||||||
|
else
|
||||||
|
NEW_DISK=""
|
||||||
|
for d in $(lsblk -ndo NAME,TYPE,FSTYPE | awk '$2=="disk" && $3=="" {print $1}'); do
|
||||||
|
if ! lsblk /dev/$d | grep -q part; then
|
||||||
|
NEW_DISK="$d"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$NEW_DISK" ]; then
|
||||||
|
log "ERRORE: nessun disco nuovo trovato"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DISK="/dev/$NEW_DISK"
|
||||||
|
fi
|
||||||
|
|
||||||
|
DISK_SIZE=$(lsblk -ndo SIZE $DISK)
|
||||||
|
|
||||||
|
log "Nuovo disco corretto: ${GREEN}$DISK ($DISK_SIZE)${RESET}"
|
||||||
|
|
||||||
|
# --- VG e LV del mountpoint root ---
|
||||||
|
ROOT_SOURCE=$(findmnt -n -o SOURCE /)
|
||||||
|
if [ -z "$ROOT_SOURCE" ] || [[ "$ROOT_SOURCE" != /dev/* ]]; then
|
||||||
|
log "ERRORE: impossibile determinare il device root da /"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ROOT_FSTYPE=$(findmnt -n -o FSTYPE /)
|
||||||
|
LV="$ROOT_SOURCE"
|
||||||
|
VG=$(lvs --noheadings -o vg_name "$LV" 2>/dev/null | awk '{$1=$1; print}')
|
||||||
|
|
||||||
|
if [ -z "$VG" ]; then
|
||||||
|
log "ERRORE: il device root ($LV) non risulta un Logical Volume LVM"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Volume Group: $VG"
|
||||||
|
log "Logical Volume: $LV"
|
||||||
|
log "Filesystem root: $ROOT_FSTYPE"
|
||||||
|
|
||||||
|
# --- Operazioni ---
|
||||||
|
run "pvcreate $DISK"
|
||||||
|
run "vgextend $VG $DISK"
|
||||||
|
run "lvextend -l +100%FREE $LV"
|
||||||
|
|
||||||
|
case "$ROOT_FSTYPE" in
|
||||||
|
ext2|ext3|ext4)
|
||||||
|
if ! command -v resize2fs >/dev/null 2>&1; then
|
||||||
|
log "ERRORE: resize2fs non trovato ma richiesto per filesystem $ROOT_FSTYPE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
run "resize2fs $LV"
|
||||||
|
;;
|
||||||
|
xfs)
|
||||||
|
if ! command -v xfs_growfs >/dev/null 2>&1; then
|
||||||
|
log "ERRORE: xfs_growfs non trovato ma richiesto per filesystem xfs"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
run "xfs_growfs /"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log "ERRORE: filesystem root non supportato: $ROOT_FSTYPE"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- Spazio finale ---
|
||||||
|
END_SIZE=$(df -BG / | awk 'NR==2 {print $2}' | tr -d 'G')
|
||||||
|
DELTA=$((END_SIZE - START_SIZE))
|
||||||
|
|
||||||
|
echo -e "${GREEN}"
|
||||||
|
echo "====================================="
|
||||||
|
echo " LVM EXTENSION COMPLETATA"
|
||||||
|
echo "-------------------------------------"
|
||||||
|
echo " Disco aggiunto : $DISK"
|
||||||
|
echo " Dimensione : $DISK_SIZE"
|
||||||
|
echo " Spazio prima : ${START_SIZE}G"
|
||||||
|
echo " Spazio dopo : ${END_SIZE}G"
|
||||||
|
echo " Aumento : +${DELTA}G"
|
||||||
|
echo "====================================="
|
||||||
|
echo -e "${RESET}"
|
||||||
|
|
||||||
|
log "Spazio iniziale: ${START_SIZE}G"
|
||||||
|
log "Spazio finale : ${END_SIZE}G"
|
||||||
|
log "Aumento : +${DELTA}G"
|
||||||
|
log "Operazione completata"
|
||||||
|
log "=========================================="
|
||||||
Reference in New Issue
Block a user