From 7be271cc9b7a607fdaa763a6a9fdb5fca3aff036 Mon Sep 17 00:00:00 2001 From: "marco.locatelli@steamware.net" Date: Wed, 21 Jan 2026 11:03:33 +0100 Subject: [PATCH] primo commit - upload scripts in usr/local/bin di pve04 --- bin/checkLogReplica.sh | 27 ++++++++++++++++++ bin/checkSwap.sh | 23 +++++++++++++++ bin/cleanReplicaSnapshot.sh | 40 ++++++++++++++++++++++++++ bin/pve-disk-monitor.sh | 54 +++++++++++++++++++++++++++++++++++ bin/pve-disk-temp.sh | 49 ++++++++++++++++++++++++++++++++ bin/pve-remove-nag.sh | 45 +++++++++++++++++++++++++++++ bin/startup_check.sh | 56 +++++++++++++++++++++++++++++++++++++ 7 files changed, 294 insertions(+) create mode 100644 bin/checkLogReplica.sh create mode 100644 bin/checkSwap.sh create mode 100644 bin/cleanReplicaSnapshot.sh create mode 100644 bin/pve-disk-monitor.sh create mode 100644 bin/pve-disk-temp.sh create mode 100644 bin/pve-remove-nag.sh create mode 100644 bin/startup_check.sh diff --git a/bin/checkLogReplica.sh b/bin/checkLogReplica.sh new file mode 100644 index 0000000..1da67b4 --- /dev/null +++ b/bin/checkLogReplica.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +echo "------------------------------------------------------------" +echo " REPORT ERRORI REPLICA PROXMOX (Ultime 24 ore)" +echo "------------------------------------------------------------" + +# Percorso dei log di replica +LOG_DIR="/var/log/pve/replicate" + +if [ ! -d "$LOG_DIR" ]; then + echo "Errore: Directory log non trovata." + exit 1 +fi + +# Trova tutti i file di log modificati nelle ultime 24h che contengono "error" o "timeout" +find $LOG_DIR -mtime -1 -type f -name "*" | while read logfile; do + if grep -qiE "error|timeout|failed" "$logfile"; then + VMID=$(basename "$logfile") + LAST_ERR=$(grep -iE "error|timeout|failed" "$logfile" | tail -n 1) + TIMESTAMP=$(stat -c %y "$logfile" | cut -d'.' -f1) + echo "ID: $VMID | Ultimo Errore: $TIMESTAMP" + echo "Dettaglio: $LAST_ERR" + echo "------------------------------------------------------------" + fi +done + +echo "Suggerimento: Controlla 'zpool iostat -v 5' durante il prossimo job." \ No newline at end of file diff --git a/bin/checkSwap.sh b/bin/checkSwap.sh new file mode 100644 index 0000000..4bd2e37 --- /dev/null +++ b/bin/checkSwap.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Monitor zSwap Status + +pagesize=$(getconf PAGESIZE) +stored_pages=$(cat /sys/kernel/debug/zswap/stored_pages) +pool_total_size=$(cat /sys/kernel/debug/zswap/pool_total_size) + +if [ "$stored_pages" -gt 0 ]; then + # Calcolo dei MB + original_size_mb=$(( stored_pages * pagesize / 1024 / 1024 )) + compressed_size_mb=$(( pool_total_size / 1024 / 1024 )) + + # Calcolo rapporto + ratio=$(echo "scale=2; $original_size_mb / $compressed_size_mb" | bc) + + echo "=== Statistiche zSwap ===" + echo "Dati Originali: ${original_size_mb} MB" + echo "Dati Compressi: ${compressed_size_mb} MB" + echo "Rapporto Comp.: ${ratio}x" + echo "Pagine su Disco: $(cat /sys/kernel/debug/zswap/written_back_pages)" +else + echo "zSwap è attivo ma al momento non ci sono dati compressi." +fi \ No newline at end of file diff --git a/bin/cleanReplicaSnapshot.sh b/bin/cleanReplicaSnapshot.sh new file mode 100644 index 0000000..73e97a3 --- /dev/null +++ b/bin/cleanReplicaSnapshot.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Verifica se il parametro --force è presente +DRY_RUN=true +if [[ "$1" == "--force" ]]; then + DRY_RUN=false +fi + +echo "--------------------------------------------------------" +echo "--- Snapshot di replica più vecchi di 24 ore ---" +echo "--------------------------------------------------------" + +# Troviamo gli snapshot, calcoliamo la data di creazione e filtriamo +zfs list -t snapshot -H -o name,creation | grep "__replicate_" | while read -r line; do + SNAP_NAME=$(echo $line | awk '{print $1}') + # Estraiamo la data (formato semplice per confronto) + CREATION_DATE=$(echo $line | awk '{print $2" "$3" "$4" "$5" "$6}') + + # Trasformiamo la data in secondi per il confronto + SNAP_SEC=$(date -d "$CREATION_DATE" +%s) + NOW_SEC=$(date +%s) + DIFF_HOURS=$(( ($NOW_SEC - $SNAP_SEC) / 3600 )) + + if [ $DIFF_HOURS -gt 24 ]; then + if [ "$DRY_RUN" = true ]; then + echo "DA ELIMINARE: $SNAP_NAME (Età: $DIFF_HOURS ore)" + # Qui non eseguiamo il comando reale + else + echo "Eliminazione effettiva dello snapshot: $snapshot" + zfs destroy $SNAP_NAME + fi + fi +done + +if [ "$DRY_RUN" = true ]; then + echo "--------------------------------------------------------" + echo "" + echo "Operazione completata in modalità simulazione." + echo "Per eliminare realmente, usa: $0 --force" +fi diff --git a/bin/pve-disk-monitor.sh b/bin/pve-disk-monitor.sh new file mode 100644 index 0000000..c499606 --- /dev/null +++ b/bin/pve-disk-monitor.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Colori +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +BLUE='\033[0;34m' +NC='\033[0m' + +# Intestazione +printf "${BLUE}%-12s %-10s %-8s %-12s %-25s${NC}\n" "DEVICE" "TYPE" "TEMP" "WRITE/s" "MODEL" +echo "--------------------------------------------------------------------------" + +# Raccoglie dati I/O in un colpo solo (campionamento 1s) +# Estraiamo i KB scritti al secondo (colonna 4 di iostat -dk) +io_stats=$(iostat -dk 1 2 | awk '/^Device/ {d=1;next} d && /^[^ ]/ {print $1,$4}') + +for disk_path in $(lsblk -dnpo NAME | grep -vE "loop|rbd|zd"); do + dev_name=$(basename "$disk_path") + + # 1. Recupero Temperatura + if [[ "$dev_name" == *"nvme"* ]]; then + type="NVMe" + temp=$(smartctl -a "$disk_path" | grep -i "Temperature:" | awk '{print $2}' | head -n 1) + else + type="SATA/SAS" + temp=$(smartctl -A "$disk_path" | grep -E "Temperature_Celsius|Airflow_Temperature_Cel" | awk '{print $10}' | head -n 1) + fi + + # 2. Recupero Scrittura (da stats iostat salvate) + write_kb=$(echo "$io_stats" | grep "^$dev_name " | tail -n 1 | awk '{print $2}') + [ -z "$write_kb" ] && write_kb="0" + + # Formattazione Scrittura (MB/s se > 1024 KB) + if (( $(echo "$write_kb > 1024" | bc -l) )); then + write_out=$(echo "scale=1; $write_kb / 1024" | bc -l | xargs printf "%.1f MB/s") + else + write_out="${write_kb} KB/s" + fi + + # 3. Colore Temperatura + if [[ "$temp" =~ ^[0-9]+$ ]]; then + if [ "$temp" -ge 60 ]; then t_color=$RED; elif [ "$temp" -ge 45 ]; then t_color=$YELLOW; else t_color=$GREEN; fi + temp_out="${t_color}${temp}°C${NC}" + else + temp_out="N/A" + fi + + # 4. Modello + model=$(smartctl -i "$disk_path" | grep -i "Device Model:\|Model Number:" | cut -d: -f2 | xargs) + + # Stampa riga + printf "%-12s %-10s %-18b %-12s %-25s\n" "$dev_name" "$type" "$temp_out" "$write_out" "$model" +done \ No newline at end of file diff --git a/bin/pve-disk-temp.sh b/bin/pve-disk-temp.sh new file mode 100644 index 0000000..bbcaec1 --- /dev/null +++ b/bin/pve-disk-temp.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# Colori per le soglie +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +# Intestazione allineata +printf "%-12s %-10s %-8s %-25s\n" "DEVICE" "TYPE" "TEMP" "MODEL" +echo "------------------------------------------------------------" + +# Elenca tutti i dischi fisici escludendo partizioni e device virtuali +for disk in $(lsblk -dnpo NAME | grep -vE "loop|rbd|zd"); do + + # Rileva il tipo di disco + if [[ "$disk" == *"nvme"* ]]; then + type="NVMe" + # Per NVMe usiamo nvme-cli o smartctl (più universale) + temp=$(smartctl -a $disk | grep -i "Temperature:" | awk '{print $2}' | head -n 1) + else + type="SATA/SAS" + # Per SSD/HDD cerchiamo Temperature_Celsius o Airflow_Temperature + temp=$(smartctl -A $disk | grep -E "Temperature_Celsius|Airflow_Temperature_Cel" | awk '{print $10}' | head -n 1) + fi + + # Se non trova la temperatura (alcuni controller RAID o dischi vecchi) + if [ -z "$temp" ]; then temp="N/A"; fi + + # Estrazione modello + model=$(smartctl -i $disk | grep -i "Device Model:\|Model Number:" | cut -d: -f2 | xargs) + + # Logica colori per la temperatura + if [[ "$temp" =~ ^[0-9]+$ ]]; then + if [ "$temp" -ge 60 ]; then + t_color=$RED + elif [ "$temp" -ge 45 ]; then + t_color=$YELLOW + else + t_color=$GREEN + fi + temp_out="${t_color}${temp}°C${NC}" + else + temp_out="N/A" + fi + + # Stampa riga + printf "%-12s %-10s %-18b %-25s\n" "$(basename $disk)" "$type" "$temp_out" "$model" +done \ No newline at end of file diff --git a/bin/pve-remove-nag.sh b/bin/pve-remove-nag.sh new file mode 100644 index 0000000..345342f --- /dev/null +++ b/bin/pve-remove-nag.sh @@ -0,0 +1,45 @@ +#!/bin/sh +WEB_JS=/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js +if [ -s "$WEB_JS" ] && ! grep -q NoMoreNagging "$WEB_JS"; then + echo "Patching Web UI nag..." + sed -i -e "/data\.status/ s/!//" -e "/data\.status/ s/active/NoMoreNagging/" "$WEB_JS" +fi + +MOBILE_TPL=/usr/share/pve-yew-mobile-gui/index.html.tpl +MARKER="" +if [ -f "$MOBILE_TPL" ] && ! grep -q "$MARKER" "$MOBILE_TPL"; then + echo "Patching Mobile UI nag..." + printf "%s\n" \ + "$MARKER" \ + "" \ + "" >> "$MOBILE_TPL" +fi \ No newline at end of file diff --git a/bin/startup_check.sh b/bin/startup_check.sh new file mode 100644 index 0000000..fc25a04 --- /dev/null +++ b/bin/startup_check.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Colori +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# Formato colonne: ID(8) TYPE(6) ORDER(7) DELAY(7) NAME +HEADER_FMT="%-8s %-6s %-7s %-7s %-s\n" + +# Funzione per modificare l'ordine +if [ "$1" != "" ] && [ "$2" != "" ]; then + VMID=$1 + ORDER=$2 + DELAY=${3:-0} # Default a 0 se non specificato + + if [ -f "/etc/pve/qemu-server/$VMID.conf" ]; then + qm set $VMID --startup order=$ORDER,up=$DELAY + echo -e "${GREEN}Configurato startup per VM $VMID: ordine $ORDER, delay ${DELAY}s${NC}" + elif [ -f "/etc/pve/lxc/$VMID.conf" ]; then + pct set $VMID --startup order=$ORDER,up=$DELAY + echo -e "${GREEN}Configurato startup per CT $VMID: ordine $ORDER, delay ${DELAY}s${NC}" + else + echo -e "${YELLOW}Errore: VM/CT $VMID non trovato.${NC}" + fi + exit 0 +fi + +# Funzione per visualizzare +show_table() { + filter=$1 + for conf_path in /etc/pve/qemu-server/*.conf /etc/pve/lxc/*.conf; do + [ -e "$conf_path" ] || continue + vmid=$(basename "$conf_path" .conf) + [[ "$conf_path" == *"/qemu-server/"* ]] && type="VM" || type="CT" + name=$(grep -m 1 -E "^(name|hostname):" "$conf_path" | cut -d: -f2- | xargs) + startup=$(grep "startup:" "$conf_path") + + if [ "$filter" == "with" ] && [ -n "$startup" ]; then + order=$(echo $startup | grep -oP 'order=\K\d+' || echo "0") + up=$(echo $startup | grep -oP 'up=\K\d+' || echo "0") + printf "$HEADER_FMT" "$vmid" "$type" "$order" "${up}s" "$name" + elif [ "$filter" == "without" ] && [ -z "$startup" ]; then + printf "$HEADER_FMT" "$vmid" "$type" "--" "--" "$name" + fi + done +} + +echo -e "${GREEN}=== CONFIGURATI (Ordinati per Priorità) ===${NC}" +printf "${BLUE}$HEADER_FMT${NC}" "ID" "TYPE" "ORDER" "DELAY" "NAME" +show_table "with" | sort -k3,3n + +echo -e "\n${YELLOW}=== NON CONFIGURATI (Default) ===${NC}" +printf "${BLUE}$HEADER_FMT${NC}" "ID" "TYPE" "ORDER" "DELAY" "NAME" +show_table "without" | sort -n \ No newline at end of file