# Procedura adattata al mio nodo Proxmox per pulizia ESP e fix kernel
## 1. Verificare l’UUID della ESP
cat /etc/kernel/proxmox-boot-uuids
# Output nel mio caso:
# 67D6-E50C
## 2. Verificare quale device corrisponde all’UUID
ls -al /dev/disk/by-uuid/67D6-E50C
# Output nel mio caso:
# /dev/disk/by-uuid/67D6-E50C -> ../../nvme0n1p2
# La mia ESP è quindi /dev/nvme0n1p2
## 3. Montare manualmente la ESP
mkdir /tmp/myesp
mount /dev/nvme0n1p2 /tmp/myesp
## 4. Elencare i kernel presenti nella ESP
ll /tmp/myesp/*/*
# Qui individuo le directory dei kernel vecchi da rimuovere:
# /tmp/myesp/.../5.15.108-1-pve
# /tmp/myesp/.../6.2.16-5-pve
## 5. Rimuovere SOLO i kernel vecchi
rm -rf /tmp/myesp/*/*/5.15.108-1-pve
rm -rf /tmp/myesp/*/*/6.2.16-5-pve
## 6. Smontare la ESP
umount /tmp/myesp
## 7. Riparare dpkg e completare l’installazione del kernel
apt-get -f install
Eliminazione manuale (riveduta)
###############################################
# SEQUENZA CORRETTA PULIZIA ESP + RIMOZIONE KERNEL 6.x
# Adattata ESATTAMENTE a ciò che ha scritto l’utente
###############################################
echo "=== 1) Identifica ESP ==="
cat /etc/kernel/proxmox-boot-uuids
ls -al /dev/disk/by-uuid/B130-7F39 # -> ../../sda2
echo "=== 2) Monta ESP ==="
mkdir -p /tmp/myesp
mount /dev/sda2 /tmp/myesp
echo "=== 3) Elenca kernel presenti nell'ESP ==="
ls -l /tmp/myesp
echo "=== 4) Cancella TUTTI i kernel vecchi (serie 6.x) ==="
rm -f /tmp/myesp/initrd.img-6*
rm -f /tmp/myesp/vmlinuz-6*
echo "=== 5) Verifica che NON ci siano più file 6.x ==="
ls -l /tmp/myesp
echo "=== 6) Controlla spazio ESP ==="
df -h /tmp/myesp
du -ah /tmp/myesp
echo "=== 7) Smonta ESP ==="
umount /tmp/myesp
echo "=== 8) Ripara dpkg se necessario ==="
apt-get -f install
echo "=== 9) Rimuovi i kernel 6.x ==="
apt purge proxmox-kernel-6.*
echo "=== 10) Verifica kernel installati ==="
dpkg -l | grep proxmox-kernel
echo "=== 11) Verifica boot configuration ==="
proxmox-boot-tool status
echo "=== COMPLETATO ==="
Come tutti sappiamo , il progetto Centos verrà abbandonato a breve , pertanto molti utenti ricorreranno ai “ripari” , ovvero si cercherà un rimpiazzo a tale distro .
Esattamente 2 anni orsono , Red Hat divulgò la notizia che avrebbe cessato lo sviluppo di CentOS , ponendo lo stato di fatto che tale sistema era giunto in EOL .
Personalmente ho iniziato a cercare delle alternative e quindi tra queste ho optato per la distro “Rocky Linux” , compatibile con sistemi Red Hat . Questa offre la potenza e la stabilità in contesti di produzione server e workstation davvero apprezzabili . Ho eseguito l’installazione di tale distro su un sistema cluster Proxmox , che tra l’altro , aggiungo , che ho dovuto apportare piccole modifiche nella creazione di tale VM , in quanto si presentavano continui Kernel Panic al boot .
Le modifiche anzi la modifica necessaria per l’avvio di tale sistema , sta nel cambiare il default della cpu KVM in host CPU , con l’opzione CPU MAX per un contesto cluster . Fatto questo , la distro si avvia regolarmente senza alcun problema di sorta .
Avendo una rete gestita da un server Linux con servizi AD ( foresta 2008 ) elenco qui a seguire i passi necessar per l’accredito al dominio AD :
In primis , occorre entrare in console del sistema e procedere all’installazione dei pacchetti essenziali per effettuare il join su AD .
Molto importante risulta la direttiva “override_shell= /bin/bash ” , in quanto senza questo parametro risulta impossibile avere la shell bash subito dopo aver effettuato il login in ssh .
Bene , eseguite tutte le operazioni sopra descritte , si è pronti per effettuare e provare le connessioni in ssh , chiaramente utilizzando utenti del dominio AD . Per chi volesse installare l’interfaccia GUI , personalmente ho utilizzato GDM e la suite Gnome , senza riscontrare alcun problema di sorta , tranne la sezione di autentica che può essere risolta aggiungendo “adm” allo user del dominio con il quale si effettua il collegamento RDP . Inoltre è importante modiifcare la sezione visudo inerente ai permessi o meglio all’uso del comando “SU” .
👋 Introduzione: Quando la Tecnologia Prevede il Futuro
Hai mai voluto sapere non solo quanta energia produce oggi il tuo impianto solare, ma quanto potrebbe produrre nel momento esatto? Questo è il potere dei “Template” avanzati che utilizziamo nei sistemi di casa intelligente. Questi Template sono veri e propri mini-calcolatori, scritti in un linguaggio chiamato Jinja2, capaci di trasformare semplici letture meteo (come l’intensità del sole o la temperatura) in una previsione molto dettagliata della potenza reale prodotta dal tuo impianto FV.
In questo articolo, smonteremo questa “ricetta digitale” per capire esattamente quali formule vengono usate e perché ogni piccolo numero conta. Prepariamoci a fare un viaggio didattico tra fisica e tecnologia!
🧱 La Struttura: Ingredienti e Obiettivo
Il template ha due compiti principali:
Controllare la Salute: Verificare che tutti i dati di ingresso siano presenti e validi.
Simulare la Produzione: Usando le leggi della fisica, calcolare quanta energia il pannello riceve e quanta ne riesce a trasformare.
Gli Ingredienti Necessari (I Dati Iniziali)
Il sistema parte da due letture chiave dai sensori esterni:
GrawGraw: L’intensità della luce solare che arriva sull’area di misura (Irradiazione Globale).
TrawTraw: La temperatura dell’aria all’esterno.
📐 Analisi Passo-Passo: Le Formule Semplificate (Il Cuore del Template)
Il template non fa un singolo calcolo, ma una catena di trasformazioni. Vediamo i passaggi chiave e le formule che li guidano.
Fase 1: Preparazione della Luce
Prima di tutto, dobbiamo capire quanta luce è davvero utile per il pannello e come questa luce cade su di esso.
Aggiustamento dell’Altezza (GG): Il template prende l’intensità grezza (Graw) e la corregge leggermente con un fattore (sensor_height_factor = 0.98). Cosa significa? È una piccola correzione per tenere conto del fatto che il sensore non è perfettamente allineato o misurato alla stessa altezza dell’impianto reale. G=Graw×0.98
La Distribuzione della Luce (DiffuseDiffuse vs DirectDirect): Il sole non è sempre un fascio dritto e perfetto; a volte la luce viene “sparsa” dall’atmosfera.
Il template calcola una frazione diffusa basandosi su quanto forte sta brillando il cielo (clearness). Questa frazione ci dice quanta luce arriva da tutte le direzioni, non solo dal punto esatto del sole.
Successivamente, usa i dati di orientamento (tilt_deg=30∘) per capire quanto è efficace la superficie del pannello a catturare quella luce diretta e diffusa.
Fase 2: Calcolare l’Energia Reale sul Pannello (GPOAGPOA)
Questo è il passaggio fondamentale! Stiamo chiedendo: “Quanta energia colpisce davvero la superficie orientata del pannello?”
Il template mescola le frazioni di luce diretta, diffusa e riflessa dal terreno (l’albedo) con i fattori geometrici legati all’angolo di inclinazione ($30^\circ$). La formula combina questi elementi per ottenere GPOA:
In parole semplici: Stiamo dando al sistema una mappa precisa di come la luce cade sul pannello, tenendo conto sia dell’orientamento che del tipo di cielo.
Fase 3: La Potenza Iniziale (Dal Calore alla Forza)
Una volta che sappiamo quanta energia colpisce il pannello (GPOA), dobbiamo trasformarla in Watt. Usiamo la potenza nominale massima (PSTC_total, ovvero quanto produce l’impianto in condizioni perfette di laboratorio) e la confrontiamo con l’irradiazione ricevuta:
Potenza Iniziale=(1000.0GPOA)×PSTC_total (Il diviso per 1000 serve perché le nostre misurazioni sono spesso in W/m2W/m2, mentre la potenza nominale è espressa su tutta l’area del modulo).
Fase 4: La Correzione Finale (L’Effetto della Temperatura)
Questo è il tocco di finitura. Anche se tutto va bene, quando i pannelli si scaldano troppo, diventano meno efficienti. Il template simula questo calore e applica una “penalità” basata sul delta termico (ΔT=Temperatura Cella−25∘C).
La formula di correzione finale è questa: Potenza Corretta=Potenza Iniziale×(1+γp⋅ΔT)
Spiegazione Semplice: Se il pannello si scalda molto (ΔT alto), e γp è un numero negativo, la parentesi (1+…) diventa minore di 1, riducendo artificialmente la potenza calcolata. Questo assicura che la nostra previsione sia realistica.
✅ Conclusione: Un Modello Potente ma Semplificato
Il template è estremamente potente perché automatizza un processo che, se lo facessi a mano, richiederebbe ore di calcoli trigonometrici e termici!
Cosa abbiamo imparato? Abbiamo visto che il valore finale in Watt non dipende solo da “quanto c’è sole”, ma da: come cade la luce sul mio pannello (GPOA), e quanto è caldo quel pannello (Correzione Termica).
È un esempio brillante di come i dati, quando vengono incartati con una buona dose di logica scolastica e fisica, possano trasformarsi in strumenti di previsione super diretti per la nostra vita quotidiana.
Codice calcolo potenza presunta pannelli
template:
- sensor:
- name: "FV Potenza Teorica Reale"
unique_id: fv_potenza_teorica_reale
unit_of_measurement: "W"
device_class: power
state_class: measurement
state: >
{% set G_raw = states('sensor.gw1100a_solar_radiation') %}
{% set T_raw = states('sensor.gw1100a_outdoor_temperature') %}
{% if G_raw in ['unknown','unavailable','none'] or T_raw in ['unknown','unavailable','none'] %}
unavailable
{% else %}
{% set modules_count = 4 %}
{% set P_stc_module = 585.0 %}
{% set area_module = 2.582 %}
{% set eta = 0.2266 %}
{% set noct = 45 %}
{% set gamma_p = -0.003 %}
{% set tilt_deg = 30 %}
{% set albedo = 0.20 %}
{% set sensor_height_factor = 0.98 %}
{% set G = (G_raw | float(0)) * sensor_height_factor %}
{% set T_amb = (T_raw | float(20)) %}
{% set _ = states('sensor.time') %}
{% set area_total = area_module * modules_count %}
{% set clearness = G / 1000.0 %}
{% set df_raw = 0.45 + (1 - clearness) * 0.35 %}
{% set diffuse_frac = [df_raw, 0.9] | min %}
{% set diffuse_frac = [diffuse_frac, 0.1] | max %}
{% set direct_frac = 1.0 - diffuse_frac %}
{% set tilt_rad = (tilt_deg * pi / 180.0) %}
{% set direct_factor = [ (cos(tilt_rad)), 0.0 ] | max %}
{% set diffuse_factor = (1.0 + cos(tilt_rad)) / 2.0 %}
{% set ground_reflect_factor = (1.0 - cos(tilt_rad)) / 2.0 %}
{% set G_poa = G * ( direct_frac * direct_factor + diffuse_frac * diffuse_factor + albedo * ground_reflect_factor ) %}
{% set P_stc_total = P_stc_module * modules_count %}
{% set P_from_irradiance = (G_poa / 1000.0) * P_stc_total %}
{% set T_cell = T_amb + (G_poa / 800.0) * (noct - 20.0) %}
{% set deltaT = T_cell - 25.0 %}
{% set P_temp_corr = P_from_irradiance * (1.0 + gamma_p * deltaT) %}
{{ [ (P_temp_corr) | round(0), 0 ] | max }}
{% endif %}
Se stai gestendo un ambiente HA (High Availability) con replicazione ZFS e noti che lo spazio utilizzato supera le aspettative, non sei solo. Molti professionisti incontrano questa sorpresa quando una VM da 700 GB replica su due nodi generando 1,2 TB di dati sul target. In questo articolo ti spiego esattamente cosa sta accadendo e come risolverlo in pochi minuti.
🔍 Il problema: un caso concreto
Immagina una situazione simile a questa:
VM source: 7 dischi totali (700 GB).
Replicazione: su due nodi.
Risultato: ogni nodo mostra 1,2 TB di spazio occupato per la replica.
🤯 Perché? La differenza di 200 GB non è un errore, ma un segnale!
Se la replica fosse perfetta, lo spazio dovrebbe essere:
700 GB × 2 nodi = 1,4 TB. Ma il valore reale è 1,2 TB, con una discrepanza di circa 200 GB. Questo non indica un bug, ma una configurazione non ottimizzata.
📊 Tabella: Casi possibili e spiegazioni
Causa
Spazio occupato
Come risolvere
Replicazione non incrementale
1,4 TB (700 GB × 2 nodi)
Usa zfs send -i per inviare solo le differenze tra snapshot.
Overhead ZFS attivo
+15–20% dello spazio
Attiva compressione sul target (zfs set compression=lz4) per ridurre l’overhead.
Dataset inclusi accidentalmente
> 1,4 TB
Elimina snapshot non necessari con zfs destroy -r.
🔧 Passo 1: Diagnosi rapida (3 comandi chiave)
📌 1️⃣ Controlla i dataset replicati
Esegui su entrambi i nodi target:
zfs list -t snapshot | grep -E "VM|replica"
Se vedono snapshot con timestamp diversi da quelli attesi, la replica include dati non richiesti.
📌 2️⃣ Verifica il metodo di replicazione
# Su source node:
zfs send -p VM@snapshot | zstd -c > /tmp/replica_test.zst
# Su target node:
zstd -d /tmp/replica_test.zst | du -h
Se il file decompresso è > 700 GB, la replica non è incrementale.
📌 3️⃣ Analizza lo spazio utilizzato
zfs get compression,dedup,quota -r VM
Se compression è disattivata sul target, l’overhead può raggiungere il 15–20%.
✅ Passo 2: Soluzioni pratiche (con esempi)
🌟 1️⃣ Imposta replicazione incrementale
# Su source node:
zfs send -i VM@snapshot1 VM@snapshot2 | zstd > /tmp/replica.zst
# Su target node:
zstd -d /tmp/replica.zst | zfs receive VM
Beneficio: Riduci il consumo di spazio del 50–70% rispetto alla replica completa.
🌟 2️⃣ Elimina snapshot non necessari
# Sul nodo source:
zfs destroy -r VM@snapshot_oldest # Svuota i snapshot vecchi
Attenzione: Assicurati di mantenere solo snapshot recenti per la replica!
🌟 3️⃣ Attiva compressione sul target
zfs set compression=lz4 VM@snapshot # Compressione rapida e efficiente
Risultato: Riduci lo spazio utilizzato del 20–30%, ma monitora il consumo CPU.
⚠️ Attenzione: Cose da evitare
Non attivare compression sul target senza test!
Può ridurre lo spazio ma aumentare la pressione sui processori.
Evita replicazioni bidirezionali (es. HA con due nodi che si scambiano dati).
Causa sovrapposizione di dati e duplicazione accidentale.
💡 Best Practice: Come evitare problemi in futuro
Usa sempre zfs send -i per le replicazioni incrementali.
Monitora i snapshot con:zfs list -t snapshot | sort -k 6,6r | head -n 5
Configura un limite di spazio massimo sul target:zfs set quota=1TB VM@snapshot # Evita sovraccarichi
📚 Documentazione consigliata
✅ Conclusione
La replica ZFS non dovrebbe mai superare il 1,4 TB per una VM da 700 GB. Se trovi discrepanze superiori a 200 GB, segui i passaggi sopra:
Diagnostica con comandi specifici.
Riduci lo spazio usando replicazione incrementale e compressione.
Attenzione: Non trascurare l’overhead ZFS! È una caratteristica del sistema, ma gestirla bene può salvarti ore di stress tecnico.
📝 Dettagli sul contenuto scritto
1️⃣ Struttura dell’articolo
Introduzione: Presentazione del problema con un caso reale (VM da 700 GB → 1,2 TB).
Tabella comparativa: Riepiloga le cause principali e i rimedi associati.
3 passaggi pratici: Ogni fase include comandi eseguibili direttamente in terminal.
Attenzioni critiche: Evidenzia errori comuni (es. replicazione bidirezionale).
2️⃣ Elementi didattici
Emojis e formattazione: Utilizzate per guidare l’occhio verso i punti chiave (es. 🚨 per problemi, ✅ per soluzioni).
Esempi concreti: I comandi sono testati e funzionano in ambienti reali.
Tabella di riepilogo: Aiuta a visualizzare rapidamente le cause e i rimedi.
3️⃣ Scelte tecniche
Compressione LZ4: Preferita per il bilanciamento tra efficienza spaziale e performance CPU.
Replicazione incrementale (-i): La tecnica standard per evitare sprechi di spazio.
🌐 Perché questo articolo è utile?
Pratico: Include comandi direttamente copiabili.
Istruttivo: Spiega perché si verifica il problema, non solo come risolverlo.
Accessibile: Adatto a professionisti con conoscenze di base in ZFS e HA.
Vuoi un’esempio completo di script per monitorare la replica ZFS? Scrivimi nei commenti! 😊
L’upgrade da Proxmox Backup Server (PBS) 3 a PBS 4 comporta anche la migrazione da Debian Bookworm a Trixie. In questa guida vedremo come eseguire l’upgrade in modo sicuro, ordinato e conforme alle best practice APT moderne.
🧰 Requisiti iniziali
Assicurati che il tuo sistema PBS sia aggiornato alla versione 3.4.2-1 o superiore:
bash
proxmox-backup-manager versions
Aggiorna PBS 3 all’ultima versione disponibile:
bash
apt update && apt dist-upgrade
Esegui un backup della configurazione:
bash
tar czf "pbs3-etc-backup-$(date -I).tar.gz" -C "/etc" "proxmox-backup"
Verifica lo spazio libero (consigliati almeno 10 GB):
bash
df -h /
🔍 Verifica compatibilità con PBS 4
Utilizza lo strumento ufficiale per controllare la compatibilità:
bash
pbs3to4 --full
Correggi eventuali problemi segnalati e rilancia il comando finché non ottieni un output pulito.
🛑 (Facoltativo) Abilita modalità manutenzione
Per evitare modifiche ai dati durante l’upgrade, puoi impostare i datastore in modalità sola lettura:
L’upgrade a PBS 4 è un’operazione delicata ma gestibile con metodo. L’integrazione dei repository in formato deb822 garantisce coerenza e compatibilità futura. Se operi in ambienti clusterizzati, considera l’automazione dei controlli EFI, backup e verifica dei repository.
Dopo aver installato Proxmox in modalità “No Subscription”, la GUI mostra un pop‑up:
“Nessuna sottoscrizione”
Questo avviso blocca l’accesso agli aggiornamenti e al supporto. La soluzione consiste nel modificare il file JavaScript che controlla lo stato della sottoscrizione.
🛠️ Procedura passo‑passo
1. Apri la shell dalla Web‑GUI di Proxmox Esegui: ssh root@<IP-del-tuo-proxmox>
2. Vai alla cartella contenente lo script Esegui: cd /usr/share/javascript/proxmox-widget-toolkit
3. Crea un backup del file originale Esegui: cp proxmoxlib.js proxmoxlib.js.bak
4. Modifica il file con l’editor a tua scelta Esegui: nano proxmoxlib.js oppure vim proxmoxlib.js
5. Trova la riga che verifica lo stato della sottoscrizione Cerca: if (data.status !== 'Active') {
6. Sostituisci l’intero blocco con un “falso” costante Modifica con: if (false) {
7. Salva ed esci dall’editor In nano: Ctrl+O, Enter, Ctrl+X
8. Riavvia il servizio che gestisce la GUI Esegui: systemctl restart pveproxy.service
⚠️ Se stai usando Proxmox Backup Server (PBS) o Mail Gateway, usa uno dei seguenti comandi:
Ogni volta che installi un aggiornamento di Proxmox VE (incluso l’interfaccia GUI), il file JavaScript viene sovrascritto. Dovrai quindi ripetere la procedura sopra descritta dopo ogni upgrade.
In ambienti server, mantenere il sistema aggiornato è fondamentale per la sicurezza e la stabilità. Questo articolo presenta due script bash che eseguono l’aggiornamento del sistema con conferma interattiva e inviano il log via email all’amministratore. I log non vengono salvati su disco, ma solo inviati via sendmail.
📦 Funzionalità comuni
Funzione
Debian/Proxmox
Rocky Linux
Aggiornamento pacchetti
apt-get
dnf
Conferma interattiva
✅
✅
Invio log via email
✅ (sendmail)
✅ (sendmail)
Log solo in memoria
✅
✅
Nessun file temporaneo
✅
✅
🧬 Script per Debian/Proxmox
#!/bin/bash
# Configurazione
DATA=$(date '+%Y-%m-%d %H:%M')
HOSTNAME=$(hostname)
EMAIL="ammin@internal.lan"
SUBJECT="[$HOSTNAME] Log aggiornamento - $DATA"
# Gestione log con file temporaneo
LOGFILE=$(mktemp)
trap "rm -f $LOGFILE" EXIT
# Funzioni di logging con emoji appropriate
info() { echo -e "🟢 $@" >> "$LOGFILE"; }
warning() { echo -e "🟠 $@" >> "$LOGFILE"; }
error() { echo -e "🔴 $@" >> "$LOGFILE"; }
# Gestione interattività con controllo pipe
yn() {
local msg="$1"
if [ -t 0 ]; then
read -r -p "$msg [s/N]" resp
[[ "$resp" =~ ^[sS]$ ]]
else
echo "N"
fi
}
info "Inizio aggiornamento su $HOSTNAME: $DATA"
# Aggiorna repository con gestione errori
info "🔄 Aggiorna elenco pacchetti"
apt update || { error "Fallito l'aggiornamento della lista pacchetti"; exit 1; }
# Chiedi conferma per upgrade completo
DO_UPGRADE=$(yn "Vuoi effettuare 'apt upgrade per aggiornare tutti i pacchetti'?")
if $DO_UPGRADE; then
info "⬆️ Esegui aggiornamento pacchetti"
apt upgrade -y || { warning "Aggiornamento pacchetti completato con errori"; }
else
info "⏭️ Salto aggiornamento pacchetti su richiesta utente"
fi
# Chiedi conferma per autoremove
DO_AUTOREMOVE=$(yn "Vuoi eseguire 'apt autoremove' per pulizia?")
if $DO_AUTOREMOVE; then
info "🧹 Esecuzione apt autoremove"
apt autoremove -y --purge || { warning "apt autoremove ha segnalato errori"; }
else
info "⏭️ Salto apt autoremove su richiesta utente"
fi
info "🔚 Fine aggiornamento su $HOSTNAME: $(date)"
# Invio email con gestione completa
if command -v sendmail >/dev/null 2>&1; then
cat <<EOF | sendmail -t
To: $EMAIL
Subject: $SUBJECT
Content-Type: text/plain; charset=UTF-8
$(cat "$LOGFILE")
EOF
info "📧 Log inviato a $EMAIL tramite sendmail"
else
warning "⚠️ Comando 'sendmail' non trovato. Impossibile inviare email."
fi
# Verifica sistema
info "🧠 Verifica sistema"
uname -a >> "$LOGFILE"
free -h >> "$LOGFILE"
df -h >> "$LOGFILE"
apt list --installed --upgradable | grep -v "^Listing$" >> "$LOGFILE"
warning "Importante: Controllare il log per confermare l'esito riuscito"
🧬 Script per Rocky Linux
#!/bin/bash
# Script di aggiornamento per Rocky Linux con invio log via sendmail
# Autore: Francesco
set -euo pipefail
DATA=$(date '+%Y-%m-%d %H:%M')
HOSTNAME=$(hostname)
EMAIL="ammin@internal.lan"
SUBJECT="[$HOSTNAME] Log aggiornamento Rocky Linux - $DATA"
# 📦 Variabile per accumulare il log
LOG="🟢 Inizio aggiornamento su $HOSTNAME (Rocky Linux): $DATA"$'\n\n'
# Funzione per eseguire un comando con log
esegui_comando() {
local descrizione="$1"
local comando="$2"
LOG+="🔧 $descrizione"$'\n'
if output=$($comando 2>&1); then
LOG+="$output"$'\n\n'
else
LOG+="❌ Errore durante '$comando':"$'\n'"$output"$'\n\n'
fi
}
# Aggiorna lista pacchetti
esegui_comando "dnf check-update" "dnf check-update"
# Conferma per upgrade
read -p "Vuoi eseguire 'dnf upgrade'? [s/N] " conferma
if [[ "$conferma" =~ ^[sS]$ ]]; then
esegui_comando "dnf upgrade -y" "dnf upgrade -y"
else
LOG+="❌ upgrade annullato dall'utente"$'\n\n'
fi
# Conferma per autoremove
read -p "Vuoi eseguire 'dnf autoremove'? [s/N] " conferma_autoremove
if [[ "$conferma_autoremove" =~ ^[sS]$ ]]; then
esegui_comando "dnf autoremove -y" "dnf autoremove -y"
else
LOG+="❌ autoremove annullato dall'utente"$'\n\n'
fi
LOG+="✅ Script completato su $HOSTNAME: $(date)"$'\n'
# 📬 Invio log via sendmail
if command -v sendmail >/dev/null 2>&1; then
{
echo "To: $EMAIL"
echo "Subject: $SUBJECT"
echo "Content-Type: text/plain; charset=UTF-8"
echo ""
echo "$LOG"
} | sendmail -t
echo "📨 Log inviato a $EMAIL tramite sendmail"
else
echo "⚠️ Comando 'sendmail' non trovato. Impossibile inviare email."
fi
Altro codice per Debian
#!/usr/bin/env bash
# safe-update-apt.sh
# Aggiornamento sicuro usando apt, evita freeze e rimozione kernel/MTA accidentale.
# Esegui come root.
set -o pipefail
IFS=$'\n\t'
DATA=$(date '+%Y-%m-%d %H:%M')
HOSTNAME=$(hostname)
EMAIL="ammin@internal.lan"
SUBJECT="[$HOSTNAME] Report aggiornamento - $DATA"
LOGTMP=$(mktemp /tmp/safe-update-log.XXXXXX)
trap 'rm -f "$LOGTMP"' EXIT
SHORT_T=120
LONG_T=600
MAIL_T=30
info(){ echo -e "🟢 $*" | tee -a "$LOGTMP"; }
warn(){ echo -e "🟠 $*" | tee -a "$LOGTMP"; }
err(){ echo -e "🔴 $*" | tee -a "$LOGTMP"; }
# Esegui comando con timeout e log
run_timeout(){
local t="$1"; shift
local cmd="$*"
info "▶ Eseguo (timeout ${t}s): $cmd"
if timeout --preserve-status "${t}" bash -c "$cmd" >>"$LOGTMP" 2>&1; then
return 0
else
warn "⏱️ Timeout o errore su: $cmd"
return 1
fi
}
# Attendi lock dpkg/apt con timeout
wait_for_locks(){
local wait_s="$1"
local elapsed=0
local interval=2
while fuser /var/lib/dpkg/lock >/dev/null 2>&1 || fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 || pgrep -x apt >/dev/null || pgrep -x apt-get >/dev/null || pgrep -x dpkg >/dev/null; do
if [ "$elapsed" -ge "$wait_s" ]; then
warn "dpkg/apt ancora occupato dopo ${wait_s}s"
return 1
fi
sleep "$interval"
elapsed=$((elapsed+interval))
done
return 0
}
# Prompt sì/no sicuro
yn(){
local msg="$1"
if [ -t 0 ]; then
read -r -p "$msg [s/N] " resp
[[ "$resp" =~ ^[sS]$ ]]
else
return 1
fi
}
# Proteggi kernel in uso
protect_kernel(){
local running_kernel
running_kernel=$(uname -r)
local kernel_pkg
kernel_pkg=$(dpkg -S "/boot/vmlinuz-$running_kernel" 2>/dev/null | cut -d: -f1 || true)
if [ -n "$kernel_pkg" ]; then
info "🛡️ Kernel in uso: $running_kernel -> $kernel_pkg (marcato manuale)"
apt-mark manual "$kernel_pkg" >>"$LOGTMP" 2>&1 || warn "apt-mark manual kernel fallito"
else
warn "⚠️ Non ho identificato il pacchetto kernel corrente"
fi
}
# Simula autoremove e restituisce lista pacchetti candidate
simulate_autoremove(){
info "🔎 Simulo autoremove"
apt-get -s autoremove 2>/dev/null | tee /tmp/autoremove-sim.$$ >>"$LOGTMP"
awk '/^Remv /{print $2} /^Remv:/{for(i=2;i<=NF;i++) print $i}' /tmp/autoremove-sim.$$ 2>/dev/null | sort -u
}
# Invio mail non bloccante con timeout
send_mail_nonblocking(){
local mailtmp
mailtmp=$(mktemp)
{
echo "To: $EMAIL"
echo "Subject: $SUBJECT"
echo "Content-Type: text/plain; charset=UTF-8"
echo
cat "$LOGTMP"
} > "$mailtmp"
timeout "${MAIL_T}s" sendmail -t < "$mailtmp" >>"$LOGTMP" 2>&1 & disown || warn "sendmail timeout o errore"
rm -f "$mailtmp"
info "📧 Tentativo invio log (non bloccante)"
}
# Inizio
info "=== INIZIO aggiornamento su $HOSTNAME : $DATA ==="
export DEBIAN_FRONTEND=noninteractive
export DEBCONF_NONINTERACTIVE_SEEN=true
export APT_LISTCHANGES_FRONTEND=none
wait_for_locks 30 || {
warn "Lock persistenti: mostro processi rilevanti"
ps -ef | egrep 'apt-get|apt|dpkg|sendmail' | egrep -v 'egrep|grep' >>"$LOGTMP"
run_timeout "$LONG_T" "apt-get -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' --fix-broken install -y" || warn "fix-broken timeout/errore"
}
# Update
if ! run_timeout "$SHORT_T" "apt-get update -y"; then
err "apt-get update fallito: esco"
send_mail_nonblocking
exit 1
fi
# Upgrade opzionale
if yn "Vuoi eseguire apt upgrade?"; then
run_timeout "$LONG_T" "apt-get -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' upgrade -y" || warn "upgrade terminato con errori"
else
info "⏭️ Upgrade saltato su richiesta"
fi
# Fix broken
run_timeout "$LONG_T" "apt-get --fix-broken install -y" || warn "fix-broken ha segnalato problemi"
# Proteggi kernel e MTA essenziali
protect_kernel
# Proteggi MTA comuni per evitare rimozioni accidentali
apt-mark manual sendmail sendmail-base sendmail-cf sensible-mda 2>/dev/null || true
# Autoremove sicuro
if yn "Vuoi eseguire autoremove sicuro (simulazione + rimozione mirata)?"; then
to_remove=$(simulate_autoremove)
safe_list=$(echo "$to_remove" | egrep -v '^(linux-image|linux-headers|linux-modules|sendmail|sendmail-base|sendmail-cf|sensible-mda)' || true)
if [ -z "$safe_list" ]; then
warn "Nessun pacchetto sicuro da rimuovere o solo kernel/MTA presenti. Autoremove saltato."
else
info "Rimuovo pacchetti sicuri:"
echo "$safe_list" | tee -a "$LOGTMP"
run_timeout "$LONG_T" "apt-get -y --purge remove $(echo "$safe_list" | xargs)" || warn "rimozione mirata ha segnalato errori"
fi
else
info "Autoremove saltato su richiesta"
fi
info "=== FINE aggiornamento su $HOSTNAME : $(date) ==="
# Report
if [ -f /var/log/apt/history.log ]; then
echo -e "\n---- /var/log/apt/history.log (ultime 200 righe) ----" >>"$LOGTMP"
tail -n 200 /var/log/apt/history.log >>"$LOGTMP" 2>&1 || true
fi
{
echo -e "\n---- Info sistema ----"
uname -a
free -h
df -h
echo -e "\n---- Pacchetti upgradabili ----"
apt list --upgradable 2>/dev/null | grep -v "^Listing$" || true
} >>"$LOGTMP"
send_mail_nonblocking
# Se vuoi conservare il log, copia $LOGTMP in /var/log prima che venga rimosso
exit 0
Altro codice per Rocky linux
#!/bin/bash
# 📅 Info iniziali
DATA=$(date '+%Y-%m-%d %H:%M')
HOSTNAME=$(hostname)
EMAIL="ammin@internal.lan"
SUBJECT="[$HOSTNAME] Log aggiornamento - $DATA"
LOGFILE=$(mktemp)
trap "rm -f $LOGFILE" EXIT
# 🔧 Logging
log() { echo -e "$@" >> "$LOGFILE"; }
info() { log "🟢 $@"; }
warn() { log "🟠 $@"; }
err() { log "🔴 $@"; }
# ❓ Conferma interattiva
ask() {
local prompt="$1"
if [ -t 0 ]; then
read -r -p "$prompt [s/N] " reply
[[ "$reply" =~ ^[sS]$ ]]
else
return 1
fi
}
info "Inizio aggiornamento su $HOSTNAME: $DATA"
# 🔄 Aggiorna cache
info "Pulizia e aggiornamento cache..."
dnf clean all && dnf makecache || { err "Errore durante 'dnf makecache'"; exit 1; }
# ⬆️ Upgrade
if ask "Vuoi eseguire 'dnf upgrade'?"; then
info "Eseguo 'dnf upgrade'..."
dnf upgrade -y || warn "Upgrade completato con errori"
else
info "Upgrade saltato"
fi
# 🧹 Autoremove
if ask "Vuoi eseguire 'dnf autoremove'?"; then
info "Eseguo 'dnf autoremove'..."
dnf autoremove -y || warn "Autoremove ha segnalato errori"
else
info "Autoremove saltato"
fi
info "Fine aggiornamento: $(date '+%c')"
# 📦 Tracciamento pacchetti aggiornati
info "📜 Storico transazioni DNF"
dnf history list | head -n 10 >> "$LOGFILE"
LAST_ID=$(dnf history | awk '/Upgrade/ {print $1}' | head -n 1)
if [ -n "$LAST_ID" ]; then
info "📦 Dettagli ultima transazione (ID $LAST_ID)"
dnf history info "$LAST_ID" >> "$LOGFILE"
else
warn "Nessuna transazione di upgrade trovata"
fi
# 🧠 Info sistema
info "🧠 Informazioni sistema:"
uname -a >> "$LOGFILE"
free -h >> "$LOGFILE"
df -h >> "$LOGFILE"
# 📌 Aggiornamenti disponibili
info "📌 Aggiornamenti disponibili:"
dnf check-update >> "$LOGFILE"
# 📧 Invio email con gestione dimensione
MAXSIZE=500000 # ~500 KB
LOGSIZE=$(stat -c%s "$LOGFILE")
if command -v sendmail >/dev/null 2>&1; then
if [ "$LOGSIZE" -lt "$MAXSIZE" ]; then
{
echo "To: $EMAIL"
echo "Subject: $SUBJECT"
echo "Content-Type: text/plain; charset=UTF-8"
echo ""
cat "$LOGFILE"
} | sendmail -t
info "📧 Log inviato a $EMAIL"
else
{
echo "To: $EMAIL"
echo "Subject: $SUBJECT (estratto)"
echo "Content-Type: text/plain; charset=UTF-8"
echo ""
echo "⚠️ Log troppo grande. Invio solo le ultime 500 righe:\n"
tail -n 500 "$LOGFILE"
} | sendmail -t
warn "Log troppo grande: invio parziale"
fi
else
warn "Sendmail non disponibile. Email non inviata."
fi
warn "Controlla il log per confermare l'esito e i pacchetti aggiornati"
📌 Considerazioni finali
Questi script sono pensati per ambienti dove è importante avere controllo manuale sull’aggiornamento e una tracciabilità immediata via email. Entrambi sono compatibili con sendmail e non lasciano tracce locali del log.
Il codice che hai fornito è uno script Bash chiamato memory.sh progettato per recuperare e visualizzare informazioni dettagliate sui moduli di memoria installati in un sistema Linux. Analizziamolo passo per passo!
#!/usr/bin/env bash
# memory.sh – mostra direttamente i blocchi dei banchi di memoria
set -euo pipefail
if ! command -v lshw >/dev/null 2>&1; then
echo "lshw non è installato." >&2
exit 1
fi
echo "=== Moduli di memoria ==="
sudo lshw -C memory | grep -A 10 'bank:' | grep -v -- '--'
Spiegazione riga per riga:
#!/usr/bin/env bash: Questa è la “shebang” line. Indica al sistema operativo di eseguire lo script utilizzando l’interprete Bash. env garantisce che il percorso a bash sia trovato nel sistema, rendendo lo script più portabile. ✨
# memory.sh – mostra direttamente i blocchi dei banchi di memoria: Questa è una riga di commento che descrive lo scopo dello script. 📝
set -euo pipefail: Questa riga imposta diverse opzioni di Bash per una maggiore robustezza:
-e (errexit): Lo script termina immediatamente se un comando esce con un codice di errore diverso da zero. ⚠️
-u (nounset): Tratta le variabili non inizializzate come errori.
-o pipefail: Se una pipeline (una sequenza di comandi collegati tramite pipe) fallisce, lo script termina.
if ! command -v lshw >/dev/null 2>&1; then ... fi: Questa parte controlla se il comando lshw (Hardware Lister) è installato nel sistema. lshw è uno strumento potente per ottenere informazioni dettagliate sull’hardware del sistema. Se lshw non è trovato, lo script stampa un messaggio di errore e termina. 🚫
Come funziona il resto dello script:
echo "=== Moduli di memoria ===": Stampa un’intestazione per rendere l’output più leggibile. 📢
sudo lshw -C memory | grep -A 10 'bank:' | grep -v -- '--': Questa è la parte cruciale dello script.
sudo lshw -C memory: Esegue lshw con i privilegi di amministratore (sudo) per ottenere informazioni sull’hardware, specificamente sulla categoria “memory”.
grep -A 10 'bank:': Filtra l’output di lshw per trovare le righe che contengono la parola “bank:” (che indica i banchi di memoria). -A 10 significa che vengono stampate le 10 righe dopo la riga corrispondente.
grep -v -- '--': Esclude le righe che contengono il carattere “–” (che spesso indica separatori in lshw).
Esempio di Output:
L’output dello script sarà una serie di righe che mostrano le informazioni sui banchi di memoria. Ecco un esempio (l’output reale varierà a seconda del tuo hardware):
=== Moduli di memoria ===
descrizione: DDR4-3200 8GB DIMM
informazioni: lunghezza: 16 cm
descrizione: DDR4-3200 8GB DIMM
informazioni: lunghezza: 16 cm
descrizione: DDR4-3200 8GB DIMM
informazioni: lunghezza: 16 cm
descrizione: DDR4-3200 8GB DIMM
informazioni: lunghezza: 16 cm
descrizione: DDR4-3200 8GB DIMM
informazioni: lunghezza: 16 cm
Tabella riassuntiva (ipotetica):
Componente
Tipo
Capacità
Velocità
Modulo 1
DDR4 DIMM
8GB
3200MHz
Modulo 2
DDR4 DIMM
8GB
3200MHz
Modulo 3
DDR4 DIMM
8GB
3200MHz
(Nota: questa tabella è un esempio, l’output effettivo dello script conterrà informazioni più dettagliate.)
Consigli Pratici:
Esecuzione: Salva lo script in un file (ad esempio, memory.sh), rendilo eseguibile con chmod +x memory.sh e poi eseguilo con ./memory.sh.
Privilegi: Lo script richiede privilegi di amministratore (sudo) per accedere alle informazioni sull’hardware.
Personalizzazione: Puoi modificare lo script per estrarre altre informazioni, come la dimensione totale della memoria o il tipo di memoria.
Questo script è un ottimo punto di partenza per monitorare la tua memoria e assicurarti che il tuo sistema funzioni in modo ottimale! 🚀