From 4e3a4732c24b309c2b8982da910953cc60d2e592 Mon Sep 17 00:00:00 2001 From: Francesco Picone Date: Fri, 13 Feb 2026 11:32:22 +0100 Subject: [PATCH] ++ Primo Caricamento --- README.md | 172 +++++++++++++++++++++++++++++++++ auto-lvm-add-disk.sh | 222 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 394 insertions(+) create mode 100644 README.md create mode 100644 auto-lvm-add-disk.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..d5c8323 --- /dev/null +++ b/README.md @@ -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. diff --git a/auto-lvm-add-disk.sh b/auto-lvm-add-disk.sh new file mode 100644 index 0000000..6d67357 --- /dev/null +++ b/auto-lvm-add-disk.sh @@ -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 |--disk=]" + 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 "=========================================="