mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-06-28 04:06:54 +00:00
746 lines
29 KiB
Bash
746 lines
29 KiB
Bash
#!/bin/bash
|
||
#set -x
|
||
|
||
|
||
# Configuration ============================================
|
||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||
BASE_DIR="/usr/local/share/proxmenux"
|
||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||
VENV_PATH="/opt/googletrans-env"
|
||
|
||
if [[ -f "$UTILS_FILE" ]]; then
|
||
source "$UTILS_FILE"
|
||
fi
|
||
load_language
|
||
initialize_cache
|
||
|
||
|
||
CONFIG_FILE="/etc/proxmox-telegram.conf"
|
||
PID_DIR="/var/run/proxmox-telegram"
|
||
WRAPPER_PATH="/usr/local/bin/telegram-notifier-wrapper.sh"
|
||
|
||
|
||
# Crear archivo de configuración si no existe
|
||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||
cat <<EOF > "$CONFIG_FILE"
|
||
BOT_TOKEN=""
|
||
CHAT_ID=""
|
||
vm_start=0
|
||
vm_shutdown=0
|
||
vm_restart=0
|
||
vm_fail=0
|
||
update_available=0
|
||
update_complete=0
|
||
system_shutdown=0
|
||
system_problem=0
|
||
system_load_high=0
|
||
kernel_panic=0
|
||
disk_fail=0
|
||
disk_full=0
|
||
disk_io_error=0
|
||
node_disconnect=0
|
||
split_brain=0
|
||
network_down=0
|
||
network_saturation=0
|
||
firewall_issue=0
|
||
backup_complete=0
|
||
backup_fail=0
|
||
snapshot_complete=0
|
||
snapshot_fail=0
|
||
auth_fail=0
|
||
ip_block=0
|
||
user_permission_change=0
|
||
cpu_high=0
|
||
ram_high=0
|
||
temp_high=0
|
||
low_disk_space=0
|
||
EOF
|
||
chmod 600 "$CONFIG_FILE" # Proteger el archivo de configuración
|
||
fi
|
||
|
||
# Leer configuración actual
|
||
source "$CONFIG_FILE"
|
||
|
||
# Función para enviar notificaciones a Telegram (sin logging)
|
||
send_notification() {
|
||
local message="$1"
|
||
|
||
# Si el token o chat ID están vacíos → No enviar nada
|
||
if [[ -z "$BOT_TOKEN" || -z "$CHAT_ID" ]]; then
|
||
return 1
|
||
fi
|
||
|
||
# Enviar notificación a Telegram (sin output)
|
||
curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
|
||
-d "chat_id=$CHAT_ID" \
|
||
-d "text=$message" > /dev/null 2>&1
|
||
}
|
||
|
||
# Opciones para el menú
|
||
options=(
|
||
"VM y Contenedor|Inicio de VM/Contenedor|vm_start"
|
||
"VM y Contenedor|Apagado de VM/Contenedor|vm_shutdown"
|
||
"VM y Contenedor|Reinicio de VM/Contenedor|vm_restart"
|
||
"VM y Contenedor|Error en inicio de VM/Contenedor|vm_fail"
|
||
"Sistema|Nueva actualización disponible|update_available"
|
||
"Sistema|Actualización completada|update_complete"
|
||
"Sistema|Apagado del sistema|system_shutdown"
|
||
"Sistema|Problema con el sistema|system_problem"
|
||
"Sistema|Carga del sistema alta|system_load_high"
|
||
"Sistema|Kernel Panic|kernel_panic"
|
||
"Almacenamiento|Fallo de disco|disk_fail"
|
||
"Almacenamiento|Almacenamiento lleno|disk_full"
|
||
"Almacenamiento|Problemas de lectura/escritura|disk_io_error"
|
||
"Clúster|Nodo desconectado|node_disconnect"
|
||
"Clúster|Split-brain (conflicto en quorum)|split_brain"
|
||
"Red|Interfaz de red caída|network_down"
|
||
"Red|Saturación de red|network_saturation"
|
||
"Red|Problema con el firewall|firewall_issue"
|
||
"Backup y Snapshot|Backup completado|backup_complete"
|
||
"Backup y Snapshot|Backup fallido|backup_fail"
|
||
"Backup y Snapshot|Snapshot completado|snapshot_complete"
|
||
"Backup y Snapshot|Snapshot fallido|snapshot_fail"
|
||
"Seguridad|Intento de autenticación fallido|auth_fail"
|
||
"Seguridad|Bloqueos automáticos de IP|ip_block"
|
||
"Seguridad|Cambio de permisos de usuario|user_permission_change"
|
||
"Recursos|Uso alto de CPU|cpu_high"
|
||
"Recursos|Uso alto de RAM|ram_high"
|
||
"Recursos|Temperatura alta del sistema|temp_high"
|
||
"Recursos|Bajo espacio en disco|low_disk_space"
|
||
)
|
||
|
||
# Función para obtener el nombre de una VM/CT a partir de su ID
|
||
get_vm_name() {
|
||
local vmid="$1"
|
||
local name=""
|
||
|
||
if [[ -f "/etc/pve/qemu-server/$vmid.conf" ]]; then
|
||
name=$(grep -i "^name:" "/etc/pve/qemu-server/$vmid.conf" | cut -d ' ' -f2-)
|
||
elif [[ -f "/etc/pve/lxc/$vmid.conf" ]]; then
|
||
name=$(grep -i "^hostname:" "/etc/pve/lxc/$vmid.conf" | cut -d ' ' -f2-)
|
||
fi
|
||
|
||
# Siempre devolver el nombre y el ID en el mismo formato
|
||
if [[ -n "$name" ]]; then
|
||
echo "$name ($vmid)"
|
||
else
|
||
echo "$vmid"
|
||
fi
|
||
}
|
||
|
||
# Función para configurar notificaciones
|
||
configure_notifications() {
|
||
# Ordenar las opciones por categoría y descripción
|
||
IFS=$'\n' sorted_options=($(for option in "${options[@]}"; do
|
||
IFS='|' read -r category description var_name <<< "$option"
|
||
printf "%s|%s|%s\n" "$category" "$description" "$var_name"
|
||
done | sort -t'|' -k1,1 -k2,2))
|
||
unset IFS
|
||
|
||
# Crear un mapeo de índices a nombres de variables
|
||
declare -A index_to_var
|
||
index=1
|
||
|
||
# Preparar las opciones para `whiptail`
|
||
menu_items=()
|
||
for option in "${sorted_options[@]}"; do
|
||
IFS='|' read -r category description var_name <<< "$option"
|
||
|
||
# Guardar el mapeo de índice a nombre de variable
|
||
index_to_var["$index"]="$var_name"
|
||
|
||
# Formatear descripción con espacios para alinear la categoría a la derecha
|
||
formatted_item="$description"
|
||
current_length=${#formatted_item}
|
||
spaces_needed=$((50 - current_length))
|
||
|
||
for ((j = 0; j < spaces_needed; j++)); do
|
||
formatted_item+=" "
|
||
done
|
||
|
||
formatted_item+="$category"
|
||
|
||
# Marcar como ON u OFF según la configuración guardada
|
||
state="OFF"
|
||
[[ "$(eval echo \$$var_name)" -eq 1 ]] && state="ON"
|
||
|
||
menu_items+=("$index" "$formatted_item" "$state")
|
||
((index++))
|
||
done
|
||
|
||
# Mostrar menú `whiptail`
|
||
selected_indices=$(whiptail --title "$(translate "Configuración de Notificaciones a Telegram")" \
|
||
--checklist --separate-output \
|
||
"\n$(translate "Selecciona los eventos que deseas recibir:")\n" \
|
||
30 100 20 \
|
||
"${menu_items[@]}" \
|
||
3>&1 1>&2 2>&3)
|
||
|
||
local result=$?
|
||
|
||
# Si se ha seleccionado alguna opción, actualizar configuración
|
||
if [[ $result -eq 0 ]]; then
|
||
# Hacer una copia de seguridad del archivo de configuración
|
||
cp "$CONFIG_FILE" "${CONFIG_FILE}.bak" 2>/dev/null
|
||
|
||
# Establecer todas las opciones en OFF
|
||
for var_name in "${index_to_var[@]}"; do
|
||
sed -i "s/^$var_name=.*/$var_name=0/" "$CONFIG_FILE"
|
||
done
|
||
|
||
# Activar las opciones seleccionadas
|
||
for selected_index in $selected_indices; do
|
||
var_name="${index_to_var[$selected_index]}"
|
||
sed -i "s/^$var_name=.*/$var_name=1/" "$CONFIG_FILE"
|
||
done
|
||
|
||
# Recargar la configuración
|
||
source "$CONFIG_FILE"
|
||
|
||
whiptail --title "$(translate "Éxito")" \
|
||
--msgbox "$(translate "Configuración actualizada correctamente.")" 10 70
|
||
fi
|
||
}
|
||
|
||
# Función: captura eventos desde journalctl
|
||
capture_journal_events() {
|
||
# Usar un archivo para almacenar eventos ya procesados
|
||
local processed_events_file="$PID_DIR/processed_events"
|
||
|
||
# Crear directorio si no existe
|
||
mkdir -p "$PID_DIR" 2>/dev/null
|
||
|
||
# Crear el archivo si no existe
|
||
if [[ ! -f "$processed_events_file" ]]; then
|
||
touch "$processed_events_file"
|
||
fi
|
||
|
||
# Monitorear continuamente el log
|
||
while true; do
|
||
# Usar tail para el archivo de tareas de Proxmox
|
||
tail -F /var/log/pve/tasks/index 2>/dev/null | while read -r line; do
|
||
# Crear un identificador único para este evento
|
||
event_id=$(echo "$line" | md5sum | cut -d' ' -f1)
|
||
|
||
# Verificar si ya procesamos este evento
|
||
if grep -q "$event_id" "$processed_events_file" 2>/dev/null; then
|
||
continue
|
||
fi
|
||
|
||
# Añadir el ID al archivo de eventos procesados
|
||
echo "$event_id" >> "$processed_events_file"
|
||
|
||
# Limitar el tamaño del archivo de eventos procesados
|
||
tail -n 1000 "$processed_events_file" > "${processed_events_file}.tmp" 2>/dev/null && mv "${processed_events_file}.tmp" "$processed_events_file" 2>/dev/null
|
||
|
||
# Variable para controlar si el evento ya fue procesado por algún patrón
|
||
local event_processed=false
|
||
|
||
# ===== EVENTOS CRÍTICOS (INMEDIATOS) =====
|
||
|
||
# Error al iniciar VM (CRÍTICO)
|
||
if [[ "$line" =~ "Failed to start VM" ]] && [[ "$vm_fail" -eq 1 ]] && [[ "$event_processed" = false ]]; then
|
||
VM_ID=$(echo "$line" | grep -oP 'VM \K[0-9]+')
|
||
NAME=$(get_vm_name "$VM_ID")
|
||
send_notification "🚨 $(translate "CRÍTICO: Error al iniciar la VM:") $NAME"
|
||
event_processed=true
|
||
fi
|
||
|
||
# Errores de I/O de disco (CRÍTICO)
|
||
if [[ "$disk_io_error" -eq 1 ]] && [[ "$event_processed" = false ]]; then
|
||
if [[ "$line" =~ "I/O error" || "$line" =~ "read error" || "$line" =~ "write error" || "$line" =~ "blk_update_request" || "$line" =~ "buffer I/O error" ]]; then
|
||
DISK=$(echo "$line" | grep -oE "/dev/[a-zA-Z0-9]+" || echo "desconocido")
|
||
send_notification "🚨 $(translate "CRÍTICO: Error de lectura/escritura en disco:") $DISK"
|
||
event_processed=true
|
||
fi
|
||
fi
|
||
|
||
# Fallo de disco (CRÍTICO)
|
||
if [[ "$disk_fail" -eq 1 ]] && [[ "$line" =~ "disk failure" ]] && [[ "$event_processed" = false ]]; then
|
||
DISK=$(echo "$line" | grep -oE "/dev/[a-zA-Z0-9]+" || echo "desconocido")
|
||
send_notification "🚨 $(translate "CRÍTICO: Fallo de disco detectado:") $DISK"
|
||
event_processed=true
|
||
fi
|
||
|
||
# Snapshot fallido (CRÍTICO)
|
||
if [[ "$line" =~ "snapshot" ]] && [[ "$snapshot_fail" -eq 1 ]] && [[ "$line" =~ "error" ]] && [[ "$event_processed" = false ]]; then
|
||
VM_ID=$(echo "$line" | grep -oP 'TASK \K[0-9]+' || echo "")
|
||
if [[ -n "$VM_ID" ]]; then
|
||
NAME=$(get_vm_name "$VM_ID")
|
||
send_notification "🚨 $(translate "CRÍTICO: Snapshot fallido para:") $NAME"
|
||
else
|
||
send_notification "🚨 $(translate "CRÍTICO: Snapshot fallido")"
|
||
fi
|
||
event_processed=true
|
||
fi
|
||
|
||
# Backup fallido (CRÍTICO)
|
||
if [[ "$line" =~ "backup" ]] && [[ "$backup_fail" -eq 1 ]] && [[ "$line" =~ "error" ]] && [[ "$event_processed" = false ]]; then
|
||
VM_ID=$(echo "$line" | grep -oP 'TASK \K[0-9]+' || echo "")
|
||
if [[ -n "$VM_ID" ]]; then
|
||
NAME=$(get_vm_name "$VM_ID")
|
||
send_notification "🚨 $(translate "CRÍTICO: Backup fallido para:") $NAME"
|
||
else
|
||
send_notification "🚨 $(translate "CRÍTICO: Backup fallido")"
|
||
fi
|
||
event_processed=true
|
||
fi
|
||
|
||
# Intento de autenticación fallido (CRÍTICO)
|
||
if [[ "$line" =~ "authentication failure" ]] && [[ "$auth_fail" -eq 1 ]] && [[ "$event_processed" = false ]]; then
|
||
USER=$(echo "$line" | grep -oP 'user=\K[^ ]+' || echo "desconocido")
|
||
IP=$(echo "$line" | grep -oP 'rhost=\K[^ ]+' || echo "desconocida")
|
||
send_notification "🚨 $(translate "CRÍTICO: Intento de autenticación fallido:") $USER desde $IP"
|
||
event_processed=true
|
||
fi
|
||
|
||
# Problema con el firewall (CRÍTICO)
|
||
if [[ "$line" =~ "firewall" ]] && [[ "$firewall_issue" -eq 1 ]] && [[ "$line" =~ "error|block|reject" ]] && [[ "$event_processed" = false ]]; then
|
||
send_notification "🚨 $(translate "CRÍTICO: Problema con el firewall:") $line"
|
||
event_processed=true
|
||
fi
|
||
|
||
# Interfaz de red caída (CRÍTICO)
|
||
if [[ "$line" =~ "network" ]] && [[ "$network_down" -eq 1 ]] && [[ "$line" =~ "down" ]] && [[ "$event_processed" = false ]]; then
|
||
IFACE=$(echo "$line" | grep -oP 'interface \K[^ ]+' || echo "desconocida")
|
||
send_notification "🚨 $(translate "CRÍTICO: Interfaz de red caída:") $IFACE"
|
||
event_processed=true
|
||
fi
|
||
|
||
# Split-brain detectado (CRÍTICO)
|
||
if [[ "$line" =~ "Split-Brain" ]] && [[ "$split_brain" -eq 1 ]] && [[ "$event_processed" = false ]]; then
|
||
send_notification "🚨 $(translate "CRÍTICO: Split-brain detectado en el clúster")"
|
||
event_processed=true
|
||
fi
|
||
|
||
# Nodo desconectado del clúster (CRÍTICO)
|
||
if [[ "$line" =~ "quorum" ]] && [[ "$node_disconnect" -eq 1 ]] && [[ "$line" =~ "lost" ]] && [[ "$event_processed" = false ]]; then
|
||
NODE=$(echo "$line" | grep -oP 'node \K[^ ]+' || echo "desconocido")
|
||
send_notification "🚨 $(translate "CRÍTICO: Nodo desconectado del clúster:") $NODE"
|
||
event_processed=true
|
||
fi
|
||
|
||
# Kernel panic (CRÍTICO)
|
||
if [[ "$line" =~ "kernel panic" ]] && [[ "$kernel_panic" -eq 1 ]] && [[ "$event_processed" = false ]]; then
|
||
send_notification "🚨 $(translate "CRÍTICO: Kernel panic detectado")"
|
||
event_processed=true
|
||
fi
|
||
|
||
# ===== EVENTOS NO CRÍTICOS (INMEDIATOS) =====
|
||
|
||
# Inicio de VM (NO CRÍTICO pero inmediato)
|
||
if [[ "$line" =~ "qmstart" ]] && [[ "$vm_start" -eq 1 ]] && [[ "$event_processed" = false ]]; then
|
||
VM_ID=$(echo "$line" | grep -oP 'qmstart:\K[0-9]+')
|
||
NAME=$(get_vm_name "$VM_ID")
|
||
send_notification "✅ $(translate "VM comenzó con éxito:") $NAME"
|
||
event_processed=true
|
||
fi
|
||
|
||
# Apagado de VM (NO CRÍTICO pero inmediato)
|
||
if [[ "$line" =~ "qmstop" ]] && [[ "$vm_shutdown" -eq 1 ]] && [[ "$event_processed" = false ]]; then
|
||
VM_ID=$(echo "$line" | grep -oP 'qmstop:\K[0-9]+')
|
||
NAME=$(get_vm_name "$VM_ID")
|
||
send_notification "✅ $(translate "VM se detuvo con éxito:") $NAME"
|
||
event_processed=true
|
||
fi
|
||
|
||
# Reinicio de VM (NO CRÍTICO pero inmediato)
|
||
if [[ "$line" =~ "qmreset" || "$line" =~ "qmreboot" ]] && [[ "$vm_restart" -eq 1 ]] && [[ "$event_processed" = false ]]; then
|
||
VM_ID=$(echo "$line" | grep -oP '(qmreset|qmreboot):\K[0-9]+')
|
||
NAME=$(get_vm_name "$VM_ID")
|
||
send_notification "✅ $(translate "VM reinició con éxito:") $NAME"
|
||
event_processed=true
|
||
fi
|
||
|
||
# Snapshot completado (NO CRÍTICO pero inmediato)
|
||
if [[ "$line" =~ "snapshot" ]] && [[ "$snapshot_complete" -eq 1 ]] && [[ ! "$line" =~ "error" ]] && [[ "$event_processed" = false ]]; then
|
||
VM_ID=$(echo "$line" | grep -oP 'TASK \K[0-9]+' || echo "")
|
||
if [[ -n "$VM_ID" ]]; then
|
||
NAME=$(get_vm_name "$VM_ID")
|
||
send_notification "✅ $(translate "Snapshot completado para:") $NAME"
|
||
else
|
||
send_notification "✅ $(translate "Snapshot completado")"
|
||
fi
|
||
event_processed=true
|
||
fi
|
||
|
||
# Backup completado (NO CRÍTICO pero inmediato)
|
||
if [[ "$line" =~ "backup" ]] && [[ "$backup_complete" -eq 1 ]] && [[ "$line" =~ "successful" ]] && [[ "$event_processed" = false ]]; then
|
||
VM_ID=$(echo "$line" | grep -oP 'TASK \K[0-9]+' || echo "")
|
||
if [[ -n "$VM_ID" ]]; then
|
||
NAME=$(get_vm_name "$VM_ID")
|
||
send_notification "✅ $(translate "Backup completado para:") $NAME"
|
||
else
|
||
send_notification "✅ $(translate "Backup completado")"
|
||
fi
|
||
event_processed=true
|
||
fi
|
||
|
||
# Actualización completada (NO CRÍTICO pero inmediato)
|
||
if [[ "$line" =~ "update" ]] && [[ "$update_complete" -eq 1 ]] && [[ "$line" =~ "complete" ]] && [[ "$event_processed" = false ]]; then
|
||
send_notification "✅ $(translate "Actualización del sistema completada")"
|
||
event_processed=true
|
||
fi
|
||
done
|
||
|
||
# Si llegamos aquí, es porque tail -F terminó inesperadamente
|
||
sleep 5
|
||
done
|
||
}
|
||
|
||
# Función: captura eventos directos del sistema
|
||
capture_direct_events() {
|
||
# Variables para controlar la frecuencia de las notificaciones
|
||
local last_load_notification=0
|
||
local last_temp_notification=0
|
||
local last_disk_space_notification=0
|
||
local last_cpu_notification=0
|
||
local last_ram_notification=0
|
||
local last_update_notification=0
|
||
|
||
# Tiempo mínimo entre notificaciones repetitivas (en segundos)
|
||
local resource_interval=900 # 15 minutos para recursos
|
||
local update_interval=86400 # 24 horas para actualizaciones
|
||
|
||
# Variables para eventos CRÍTICOS (sin intervalo)
|
||
local disk_full_detected=false
|
||
|
||
while true; do
|
||
current_time=$(date +%s)
|
||
|
||
# ===== EVENTOS CRÍTICOS (INMEDIATOS) =====
|
||
|
||
# Disco lleno (CRÍTICO - inmediato)
|
||
if [[ "$disk_full" -eq 1 ]]; then
|
||
full_disks=$(df -h | awk '$5 == "100%" {print $1 " (100% lleno)"}')
|
||
if [[ -n "$full_disks" && "$disk_full_detected" = false ]]; then
|
||
send_notification "🚨 $(translate "CRÍTICO: Almacenamiento completamente lleno:") $full_disks"
|
||
disk_full_detected=true
|
||
elif [[ -z "$full_disks" ]]; then
|
||
disk_full_detected=false
|
||
fi
|
||
fi
|
||
|
||
# ===== EVENTOS NO CRÍTICOS (CON INTERVALO) =====
|
||
|
||
# Carga alta del sistema (NO CRÍTICO - con intervalo)
|
||
if [[ "$system_load_high" -eq 1 ]]; then
|
||
load=$(awk '{print $1}' /proc/loadavg)
|
||
if (( $(echo "$load > 5.00" | bc -l) )) && (( current_time - last_load_notification > resource_interval )); then
|
||
send_notification "⚠️ $(translate "Carga alta del sistema detectada:") $load"
|
||
last_load_notification=$current_time
|
||
fi
|
||
fi
|
||
|
||
# Actualizaciones disponibles (NO CRÍTICO - con intervalo diario)
|
||
if [[ "$update_available" -eq 1 ]] && (( current_time - last_update_notification > update_interval )); then
|
||
if command -v apt-get &>/dev/null; then
|
||
apt-get update -qq &>/dev/null
|
||
updates=$(apt list --upgradable 2>/dev/null | grep -v "Listing..." | wc -l)
|
||
if [[ $updates -gt 0 ]]; then
|
||
send_notification "ℹ️ $(translate "Actualizaciones disponibles:") $updates"
|
||
last_update_notification=$current_time
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Espacio en disco bajo (NO CRÍTICO - con intervalo)
|
||
if [[ "$low_disk_space" -eq 1 ]] && (( current_time - last_disk_space_notification > resource_interval )); then
|
||
# Comprobar particiones con más del 90% pero menos del 100% de uso
|
||
low_space=$(df -h | awk '$5 ~ /9[0-9]%/ && $5 != "100%" {print $1 " (" $5 " lleno)"}')
|
||
if [[ -n "$low_space" ]]; then
|
||
send_notification "⚠️ $(translate "Espacio en disco bajo:") $low_space"
|
||
last_disk_space_notification=$current_time
|
||
fi
|
||
fi
|
||
|
||
# Uso alto de CPU (NO CRÍTICO - con intervalo)
|
||
if [[ "$cpu_high" -eq 1 ]] && (( current_time - last_cpu_notification > resource_interval )); then
|
||
# Usar mpstat si está disponible, si no, usar top
|
||
if command -v mpstat &>/dev/null; then
|
||
cpu_usage=$(mpstat 1 1 | awk '/Average:/ {print 100 - $NF}')
|
||
else
|
||
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}')
|
||
fi
|
||
|
||
if (( $(echo "$cpu_usage > 90" | bc -l) )); then
|
||
send_notification "⚠️ $(translate "Uso alto de CPU:") $cpu_usage%"
|
||
last_cpu_notification=$current_time
|
||
fi
|
||
fi
|
||
|
||
# Uso alto de RAM (NO CRÍTICO - con intervalo)
|
||
if [[ "$ram_high" -eq 1 ]] && (( current_time - last_ram_notification > resource_interval )); then
|
||
ram_usage=$(free | awk '/Mem:/ {printf "%.2f", $3/$2 * 100}')
|
||
if (( $(echo "$ram_usage > 90" | bc -l) )); then
|
||
send_notification "⚠️ $(translate "Uso alto de RAM:") $ram_usage%"
|
||
last_ram_notification=$current_time
|
||
fi
|
||
fi
|
||
|
||
# Temperatura alta (NO CRÍTICO - con intervalo)
|
||
if [[ "$temp_high" -eq 1 ]] && (( current_time - last_temp_notification > resource_interval )); then
|
||
if command -v sensors &>/dev/null; then
|
||
# Intentar diferentes patrones para detectar la temperatura
|
||
temp=$(sensors | grep -E 'Package id 0:|Core 0:|CPU:' | head -1 | grep -oP '\+\d+\.\d+°C' | grep -oP '\d+\.\d+' || echo "0")
|
||
|
||
if [[ -n "$temp" && "$temp" != "0" ]] && (( $(echo "$temp > 80" | bc -l) )); then
|
||
send_notification "⚠️ $(translate "Temperatura alta del sistema:") $temp°C"
|
||
last_temp_notification=$current_time
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Pausa entre comprobaciones
|
||
sleep 30
|
||
done
|
||
}
|
||
|
||
# Función para configurar Telegram
|
||
configure_telegram() {
|
||
# Cargar configuración existente (si existe)
|
||
[[ -f "$CONFIG_FILE" ]] && source "$CONFIG_FILE"
|
||
|
||
# Solicitar BOT_TOKEN
|
||
BOT_TOKEN=$(whiptail --title "$(translate "Configuración de Telegram")" \
|
||
--inputbox "$(translate "Introduce tu Token de Bot de Telegram:")" 10 70 "$BOT_TOKEN" 3>&1 1>&2 2>&3)
|
||
|
||
if [[ $? -ne 0 ]]; then
|
||
return
|
||
fi
|
||
|
||
# Solicitar CHAT_ID
|
||
CHAT_ID=$(whiptail --title "$(translate "Configuración de Telegram")" \
|
||
--inputbox "$(translate "Introduce tu ID de Chat de Telegram:")" 10 70 "$CHAT_ID" 3>&1 1>&2 2>&3)
|
||
|
||
if [[ $? -ne 0 ]]; then
|
||
return
|
||
fi
|
||
|
||
# Guardar configuración en archivo
|
||
if [[ -n "$BOT_TOKEN" && -n "$CHAT_ID" ]]; then
|
||
# Hacer una copia de seguridad del archivo de configuración
|
||
cp "$CONFIG_FILE" "${CONFIG_FILE}.bak" 2>/dev/null
|
||
|
||
# Verificar si las variables ya existen en el archivo
|
||
if grep -q "^BOT_TOKEN=" "$CONFIG_FILE"; then
|
||
sed -i "s/^BOT_TOKEN=.*/BOT_TOKEN=\"$BOT_TOKEN\"/" "$CONFIG_FILE"
|
||
else
|
||
echo "BOT_TOKEN=\"$BOT_TOKEN\"" >> "$CONFIG_FILE"
|
||
fi
|
||
|
||
if grep -q "^CHAT_ID=" "$CONFIG_FILE"; then
|
||
sed -i "s/^CHAT_ID=.*/CHAT_ID=\"$CHAT_ID\"/" "$CONFIG_FILE"
|
||
else
|
||
echo "CHAT_ID=\"$CHAT_ID\"" >> "$CONFIG_FILE"
|
||
fi
|
||
|
||
# Recargar la configuración
|
||
source "$CONFIG_FILE"
|
||
|
||
# Probar la configuración inmediatamente
|
||
response=$(curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
|
||
-d "chat_id=$CHAT_ID" \
|
||
-d "text=$(translate "¡Telegram está funcionando correctamente!")")
|
||
|
||
if [[ "$response" =~ "ok\":true" ]]; then
|
||
whiptail --title "$(translate "Éxito")" \
|
||
--msgbox "$(translate "Configuración de Telegram válida. Las notificaciones serán enviadas.")" 10 70
|
||
else
|
||
whiptail --title "$(translate "Error")" \
|
||
--msgbox "$(translate "Configuración de Telegram inválida. Por favor, verifica el token y el ID de chat.")" 10 70
|
||
fi
|
||
else
|
||
whiptail --title "$(translate "Error")" \
|
||
--msgbox "$(translate "Configuración de Telegram incompleta. Por favor, proporciona tanto el token como el ID de chat.")" 10 70
|
||
fi
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
# Función para iniciar el servicio de notificaciones
|
||
start_notification_service() {
|
||
if [[ ! -f /etc/systemd/system/proxmox-telegram.service ]]; then
|
||
install_systemd_service
|
||
fi
|
||
|
||
if systemctl is-active --quiet proxmox-telegram.service; then
|
||
whiptail --title "$(translate "Información")" \
|
||
--msgbox "$(translate "El servicio de notificaciones ya está en ejecución.")" 10 70
|
||
else
|
||
systemctl start proxmox-telegram.service
|
||
if systemctl is-active --quiet proxmox-telegram.service; then
|
||
whiptail --title "$(translate "Iniciado")" \
|
||
--msgbox "$(translate "El servicio se ha iniciado correctamente.")" 10 70
|
||
else
|
||
whiptail --title "$(translate "Error")" \
|
||
--msgbox "$(translate "No se pudo iniciar el servicio de notificaciones.")" 10 70
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# Función para detener el servicio
|
||
stop_notification_service() {
|
||
if [[ -f /etc/systemd/system/proxmox-telegram.service ]]; then
|
||
if systemctl is-active --quiet proxmox-telegram.service; then
|
||
systemctl stop proxmox-telegram.service
|
||
sleep 2
|
||
fi
|
||
|
||
if ! systemctl is-active --quiet proxmox-telegram.service; then
|
||
whiptail --title "$(translate "Detenido")" \
|
||
--msgbox "$(translate "El servicio ha sido detenido correctamente.")" 10 70
|
||
else
|
||
whiptail --title "$(translate "Error")" \
|
||
--msgbox "$(translate "No se pudo detener el servicio de notificaciones.")" 10 70
|
||
fi
|
||
else
|
||
whiptail --title "$(translate "Información")" \
|
||
--msgbox "$(translate "El servicio de notificaciones no está instalado aún.")" 10 70
|
||
fi
|
||
}
|
||
|
||
# Función para verificar el estado del servicio
|
||
check_service_status() {
|
||
clear
|
||
if [[ -f /etc/systemd/system/proxmox-telegram.service ]]; then
|
||
systemctl status proxmox-telegram.service
|
||
else
|
||
echo "$(translate "El servicio no está instalado.")"
|
||
fi
|
||
echo
|
||
echo "$(translate "Pulsa Enter para volver al menú...")"
|
||
read -r
|
||
}
|
||
|
||
# Función para eliminar el servicio systemd
|
||
remove_systemd_service() {
|
||
if [[ -f /etc/systemd/system/proxmox-telegram.service ]]; then
|
||
if systemctl is-active --quiet proxmox-telegram.service; then
|
||
systemctl stop proxmox-telegram.service
|
||
fi
|
||
systemctl disable proxmox-telegram.service
|
||
rm -f /etc/systemd/system/proxmox-telegram.service
|
||
systemctl daemon-reexec
|
||
whiptail --title "$(translate "Eliminado")" \
|
||
--msgbox "$(translate "El servicio ha sido eliminado correctamente. Puedes reinstalarlo desde el menú si lo deseas.")" 10 70
|
||
else
|
||
whiptail --title "$(translate "Información")" \
|
||
--msgbox "$(translate "El servicio no existe, no se requiere eliminar nada.")" 10 70
|
||
fi
|
||
}
|
||
|
||
|
||
|
||
# Funciones requeridas por systemd
|
||
start_silent() {
|
||
mkdir -p "$PID_DIR"
|
||
|
||
capture_journal_events > /dev/null 2>&1 &
|
||
echo $! > "$PID_DIR/journal.pid"
|
||
journal_pid=$!
|
||
|
||
capture_direct_events > /dev/null 2>&1 &
|
||
echo $! > "$PID_DIR/direct.pid"
|
||
direct_pid=$!
|
||
|
||
echo $$ > "$PID_DIR/service.pid"
|
||
|
||
# Esperar que ambos procesos finalicen (mantiene vivo el servicio systemd)
|
||
wait $journal_pid
|
||
wait $direct_pid
|
||
|
||
}
|
||
|
||
stop_silent() {
|
||
kill $(cat "$PID_DIR/journal.pid" 2>/dev/null) 2>/dev/null
|
||
kill $(cat "$PID_DIR/direct.pid" 2>/dev/null) 2>/dev/null
|
||
kill $(cat "$PID_DIR/service.pid" 2>/dev/null) 2>/dev/null
|
||
rm -f "$PID_DIR"/*.pid
|
||
}
|
||
|
||
|
||
|
||
# Función para instalar el servicio como un servicio systemd
|
||
install_systemd_service() {
|
||
mkdir -p "$PID_DIR"
|
||
|
||
cat > /etc/systemd/system/proxmox-telegram.service <<EOF
|
||
[Unit]
|
||
Description=Proxmox Telegram Notification Service
|
||
After=network.target pve-cluster.service
|
||
|
||
[Service]
|
||
Type=simple
|
||
ExecStart=/bin/bash -c 'bash <(curl -fsSL https://raw.githubusercontent.com/MacRimi/ProxMenux/main/scripts/telegram-notifier.sh) start_silent'
|
||
ExecStop=/bin/bash -c 'bash <(curl -fsSL https://raw.githubusercontent.com/MacRimi/ProxMenux/main/scripts/telegram-notifier.sh) stop_silent'
|
||
Restart=on-failure
|
||
PIDFile=$PID_DIR/service.pid
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
EOF
|
||
|
||
systemctl daemon-reexec
|
||
systemctl enable proxmox-telegram.service
|
||
systemctl start proxmox-telegram.service
|
||
}
|
||
|
||
|
||
|
||
# Menú principal
|
||
main_menu() {
|
||
while true; do
|
||
# Preparar las opciones del menú
|
||
local menu_options=(
|
||
"1" "$(translate "Configurar Telegram")"
|
||
"2" "$(translate "Configurar Notificaciones")"
|
||
"3" "$(translate "Iniciar Servicio de Notificaciones")"
|
||
"4" "$(translate "Detener Servicio de Notificaciones")"
|
||
"5" "$(translate "Verificar Estado del Servicio")"
|
||
)
|
||
|
||
# Añadir la opción de eliminar servicio solo si está instalado
|
||
if [[ -f /etc/systemd/system/proxmox-telegram.service ]]; then
|
||
menu_options+=(
|
||
"6" "$(translate "Eliminar Servicio de Notificaciones")"
|
||
)
|
||
fi
|
||
|
||
# Añadir siempre la opción de salir al final
|
||
menu_options+=(
|
||
"7" "$(translate "Salir")"
|
||
)
|
||
|
||
# Mostrar el menú con las opciones preparadas
|
||
OPTION=$(whiptail --title "$(translate "Configuración de Notificaciones de Proxmox")" \
|
||
--menu "$(translate "Elige una opción:")" 20 70 10 \
|
||
"${menu_options[@]}" \
|
||
3>&1 1>&2 2>&3)
|
||
|
||
if [[ $? -ne 0 ]]; then
|
||
exit 0
|
||
fi
|
||
|
||
case "$OPTION" in
|
||
1) configure_telegram ;;
|
||
2) configure_notifications ;;
|
||
3) start_notification_service ;;
|
||
4) stop_notification_service ;;
|
||
5) check_service_status ;;
|
||
6) remove_systemd_service ;;
|
||
7) exit 0 ;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
case "$1" in
|
||
start_silent) start_silent ;;
|
||
stop_silent) stop_silent ;;
|
||
*) main_menu ;;
|
||
esac
|