mirror of
https://github.com/kelroy1990/Homelabs-Pi-Storage.git
synced 2026-08-28 10:04:27 -05:00
5913 lines
241 KiB
Bash
Executable File
5913 lines
241 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# RAID Configuration Script for Raspberry Pi / Script de Configuración RAID para Raspberry Pi
|
||
# Supports BTRFS and ZFS / Soporta BTRFS y ZFS
|
||
|
||
set -e
|
||
|
||
# Colors for output / Colores para output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Global variable for language selection
|
||
SCRIPT_LANGUAGE="en"
|
||
export SCRIPT_LANGUAGE
|
||
|
||
# Language selection function / Función de selección de idioma
|
||
select_language() {
|
||
clear
|
||
echo "╔════════════════════════════════════════════════════════════════╗"
|
||
echo "║ RAID Configuration Script ║"
|
||
echo "║ Script de Configuración RAID ║"
|
||
echo "╚════════════════════════════════════════════════════════════════╝"
|
||
echo ""
|
||
echo "Please select your preferred language / Por favor selecciona tu idioma preferido:"
|
||
echo ""
|
||
echo " 1. English"
|
||
echo " 2. Español"
|
||
echo ""
|
||
|
||
while true; do
|
||
read -p "Language choice / Elección de idioma (1-2): " lang_choice
|
||
case $lang_choice in
|
||
1)
|
||
SCRIPT_LANGUAGE="en"
|
||
export SCRIPT_LANGUAGE
|
||
echo "Language set to English"
|
||
break
|
||
;;
|
||
2)
|
||
SCRIPT_LANGUAGE="es"
|
||
export SCRIPT_LANGUAGE
|
||
echo "Idioma establecido en Español"
|
||
break
|
||
;;
|
||
*)
|
||
echo "Invalid option. Please select 1 or 2 / Opción inválida. Selecciona 1 o 2"
|
||
;;
|
||
esac
|
||
done
|
||
echo ""
|
||
sleep 1
|
||
}
|
||
|
||
# Multilingual text messages / Mensajes de texto multiidioma
|
||
get_text() {
|
||
local key="$1"
|
||
|
||
case "$key" in
|
||
"script_title")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "RAID Configuration Script for Raspberry Pi"
|
||
else
|
||
echo "Script de Configuración RAID para Raspberry Pi"
|
||
fi
|
||
;;
|
||
"root_warning")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Do not run this script as root. Use sudo when necessary."
|
||
else
|
||
echo "No ejecutes este script como root. Usa sudo cuando sea necesario."
|
||
fi
|
||
;;
|
||
"checking_requirements")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Checking System Requirements"
|
||
else
|
||
echo "Verificando Requisitos del Sistema"
|
||
fi
|
||
;;
|
||
"updating_packages")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Updating package list..."
|
||
else
|
||
echo "Actualizando lista de paquetes..."
|
||
fi
|
||
;;
|
||
"btrfs_available")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "✓ BTRFS: Available"
|
||
else
|
||
echo "✓ BTRFS: Disponible"
|
||
fi
|
||
;;
|
||
"btrfs_not_available")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "✗ BTRFS: Not available"
|
||
else
|
||
echo "✗ BTRFS: No disponible"
|
||
fi
|
||
;;
|
||
"zfs_available")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "✓ ZFS: Available"
|
||
else
|
||
echo "✓ ZFS: Disponible"
|
||
fi
|
||
;;
|
||
"zfs_not_available")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "✗ ZFS: Not available"
|
||
else
|
||
echo "✗ ZFS: No disponible"
|
||
fi
|
||
;;
|
||
"no_raid_tools")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "No RAID tools available in the system"
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "No RAID tools available on the system"
|
||
else
|
||
echo "No hay herramientas RAID disponibles en el sistema"
|
||
fi
|
||
fi
|
||
;;
|
||
"will_install_packages")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Required packages will be installed..."
|
||
else
|
||
echo "Se instalarán los paquetes necesarios..."
|
||
fi
|
||
;;
|
||
"packages_to_install")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Packages to be installed:"
|
||
else
|
||
echo "Paquetes que se instalarán:"
|
||
fi
|
||
;;
|
||
"zfs_install_warning")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "⚠️ ZFS may take up to 10 minutes to install due to kernel module compilation"
|
||
else
|
||
echo "⚠️ ZFS puede tardar hasta 10 minutos en instalarse debido a la compilación de módulos del kernel"
|
||
fi
|
||
;;
|
||
"installation_progress_shown")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "⚠️ You will see the installation progress on screen"
|
||
else
|
||
echo "⚠️ Durante la instalación verás el progreso en pantalla"
|
||
fi
|
||
;;
|
||
"continue_installation")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Do you want to continue with the installation?"
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Do you want to continue with the installation?"
|
||
else
|
||
echo "¿Deseas continuar con la instalación?"
|
||
fi
|
||
fi
|
||
;;
|
||
"installation_cancelled")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Installation cancelled by user"
|
||
else
|
||
echo "Instalación cancelada por el usuario"
|
||
fi
|
||
;;
|
||
"starting_installation")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Starting package installation..."
|
||
else
|
||
echo "Iniciando instalación de paquetes..."
|
||
fi
|
||
;;
|
||
"installing_zfs")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "🔄 Installing ZFS (this may take several minutes)..."
|
||
else
|
||
echo "🔄 Instalando ZFS (esto puede tomar varios minutos)..."
|
||
fi
|
||
;;
|
||
"zfs_progress")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "📦 ZFS Installation Progress:"
|
||
else
|
||
echo "📦 Progreso de instalación ZFS:"
|
||
fi
|
||
;;
|
||
"zfs_installed_successfully")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "✅ ZFS installed successfully"
|
||
else
|
||
echo "✅ ZFS instalado exitosamente"
|
||
fi
|
||
;;
|
||
"error_installing_zfs")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "❌ Error installing ZFS"
|
||
else
|
||
echo "❌ Error instalando ZFS"
|
||
fi
|
||
;;
|
||
"please_respond_yn")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Please answer y or n."
|
||
else
|
||
echo "Por favor responde y o n."
|
||
fi
|
||
;;
|
||
"installation_cancelled")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Installation cancelled by user"
|
||
else
|
||
echo "Instalación cancelada por el usuario"
|
||
fi
|
||
;;
|
||
"raid_completed")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "RAID configuration completed successfully!"
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "¡RAID configuration completed successfully!"
|
||
else
|
||
echo "¡Configuración RAID completada exitosamente!"
|
||
fi
|
||
fi
|
||
;;
|
||
"raid_mounted_at")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "RAID is mounted at:"
|
||
else
|
||
echo "El RAID está montado en:"
|
||
fi
|
||
;;
|
||
"detect_existing_raid")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Detecting Existing RAID Configurations"
|
||
else
|
||
echo "Detección de Configuraciones RAID Existentes"
|
||
fi
|
||
;;
|
||
"available_options")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "🛠️ AVAILABLE OPTIONS:"
|
||
else
|
||
echo "🛠️ OPCIONES DISPONIBLES:"
|
||
fi
|
||
;;
|
||
"continue_new_raid")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Continue with new RAID configuration"
|
||
else
|
||
echo "Continuar con configuración de nuevo RAID"
|
||
fi
|
||
;;
|
||
"exit_script")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Exit script"
|
||
else
|
||
echo "Salir del script"
|
||
fi
|
||
;;
|
||
"no_raid_detected")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "ℹ️ No existing RAID configurations detected."
|
||
else
|
||
echo "ℹ️ No se detectaron configuraciones RAID existentes."
|
||
fi
|
||
;;
|
||
"system_ready_new_raid")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " System is ready to configure a new RAID."
|
||
else
|
||
echo " El sistema está listo para configurar un nuevo RAID."
|
||
fi
|
||
;;
|
||
"manage_zfs_pools")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Manage ZFS pools and datasets"
|
||
else
|
||
echo "Gestionar pools y datasets ZFS"
|
||
fi
|
||
;;
|
||
"delete_zfs_pools")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Delete specific ZFS pools"
|
||
else
|
||
echo "Eliminar pools ZFS específicos"
|
||
fi
|
||
;;
|
||
"delete_btrfs_filesystems")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Delete specific BTRFS filesystems"
|
||
else
|
||
echo "Eliminar filesystems BTRFS específicos"
|
||
fi
|
||
;;
|
||
"manage_mdadm_arrays")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Manage MDADM arrays (information only)"
|
||
else
|
||
echo "Gestionar arrays MDADM (información solamente)"
|
||
fi
|
||
;;
|
||
"manage_lvm_groups")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Manage LVM Volume Groups (information only)"
|
||
else
|
||
echo "Gestionar Volume Groups LVM (información solamente)"
|
||
fi
|
||
;;
|
||
"continue_new_raid")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Continue with new RAID configuration"
|
||
else
|
||
echo "Continuar con configuración de nuevo RAID"
|
||
fi
|
||
;;
|
||
"exit_script")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Exit script"
|
||
else
|
||
echo "Salir del script"
|
||
fi
|
||
;;
|
||
"invalid_option")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "❌ Invalid option. Please select a valid number."
|
||
else
|
||
echo "❌ Opción inválida. Selecciona un número válido."
|
||
fi
|
||
;;
|
||
"select_option")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "👉 Select an option"
|
||
else
|
||
echo "👉 Selecciona una opción"
|
||
fi
|
||
;;
|
||
"continuing_new_raid")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Continuing with new RAID configuration..."
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Continuing with new RAID configuration..."
|
||
else
|
||
echo "Continuando con configuración de nuevo RAID..."
|
||
fi
|
||
fi
|
||
;;
|
||
"exiting_script")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Exiting script..."
|
||
else
|
||
echo "Saliendo del script..."
|
||
fi
|
||
;;
|
||
"manage_mdadm_arrays")
|
||
if [ "$SCRIPT_LANGUAGE" = "es" ]; then
|
||
echo "Gestionar arrays MDADM (información solamente)"
|
||
else
|
||
echo "Manage MDADM arrays (information only)"
|
||
fi
|
||
;;
|
||
"manage_lvm_groups")
|
||
if [ "$SCRIPT_LANGUAGE" = "es" ]; then
|
||
echo "Gestionar Volume Groups LVM (información solamente)"
|
||
else
|
||
echo "Manage LVM Volume Groups (information only)"
|
||
fi
|
||
;;
|
||
"delete_btrfs_filesystems")
|
||
if [ "$SCRIPT_LANGUAGE" = "es" ]; then
|
||
echo "Eliminar filesystems BTRFS específicos"
|
||
else
|
||
echo "Delete specific BTRFS filesystems"
|
||
fi
|
||
;;
|
||
"mdadm_management_info")
|
||
if [ "$SCRIPT_LANGUAGE" = "es" ]; then
|
||
echo "Para gestionar arrays MDADM, usa herramientas específicas como:"
|
||
else
|
||
echo "To manage MDADM arrays, use specific tools like:"
|
||
fi
|
||
;;
|
||
"lvm_management_info")
|
||
if [ "$SCRIPT_LANGUAGE" = "es" ]; then
|
||
echo "Para gestionar LVM, usa herramientas específicas como:"
|
||
else
|
||
echo "To manage LVM, use specific tools like:"
|
||
fi
|
||
;;
|
||
"continue_detection")
|
||
if [ "$SCRIPT_LANGUAGE" = "es" ]; then
|
||
echo "¿Continuar con la detección de configuraciones?"
|
||
else
|
||
echo "Continue with configuration detection?"
|
||
fi
|
||
;;
|
||
"sector_config_detected")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "[INFO] 📊 Detected sector configuration:"
|
||
else
|
||
echo "[INFO] 📊 Configuración de sectores detectada:"
|
||
fi
|
||
;;
|
||
"max_sector_size_hdds")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "[INFO] Maximum sector size in HDDs:"
|
||
else
|
||
echo "[INFO] Tamaño de sector máximo en HDDs:"
|
||
fi
|
||
;;
|
||
"pool_ashift")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "[INFO] Pool ashift:"
|
||
else
|
||
echo "[INFO] Ashift del pool:"
|
||
fi
|
||
;;
|
||
"compatibility_cache_devices")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "[INFO] ✅ This ensures compatibility with SSD cache devices (4096 bytes)"
|
||
else
|
||
echo "[INFO] ✅ Esto garantiza compatibilidad con cache devices SSD (4096 bytes)"
|
||
fi
|
||
;;
|
||
"config_for_pool")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "[INFO] 📊 Configuration for pool"
|
||
else
|
||
echo "[INFO] 📊 Configuración para pool"
|
||
fi
|
||
;;
|
||
"ensures_compatibility_future")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "[INFO] ✅ Ensures compatibility with future cache devices"
|
||
else
|
||
echo "[INFO] ✅ Garantiza compatibilidad con cache devices futuro"
|
||
fi
|
||
;;
|
||
*)
|
||
echo "$key" # Fallback to key itself
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# Functions for displaying messages / Funciones para mostrar mensajes
|
||
show_message() {
|
||
echo -e "${GREEN}[INFO]${NC} $1"
|
||
}
|
||
|
||
show_warning() {
|
||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||
}
|
||
|
||
show_error() {
|
||
echo -e "${RED}[ERROR]${NC} $1"
|
||
}
|
||
|
||
show_title() {
|
||
echo -e "${BLUE}=== $1 ===${NC}"
|
||
}
|
||
|
||
# Function to get user confirmation / Función para obtener confirmación del usuario
|
||
confirm() {
|
||
local prompt="$1"
|
||
local yn_text
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
yn_text="(y/n)"
|
||
else
|
||
yn_text="(s/n)"
|
||
fi
|
||
|
||
while true; do
|
||
read -p "$prompt $yn_text: " yn
|
||
case $yn in
|
||
[YySs]* ) return 0;;
|
||
[Nn]* ) return 1;;
|
||
* ) echo "$(get_text "please_respond_yn")";;
|
||
esac
|
||
done
|
||
}
|
||
|
||
# Function to check and install system requirements / Función para verificar e instalar requisitos del sistema
|
||
check_and_install_requirements() {
|
||
show_title "$(get_text "checking_requirements")"
|
||
|
||
# Update package list / Actualizar lista de paquetes
|
||
show_message "$(get_text "updating_packages")"
|
||
sudo apt update > /dev/null 2>&1
|
||
|
||
local packages_to_install=()
|
||
local missing_packages=""
|
||
|
||
# Check basic tools / Verificar herramientas básicas
|
||
if ! command -v lsblk &> /dev/null; then
|
||
packages_to_install+=("util-linux")
|
||
missing_packages="$missing_packages util-linux"
|
||
fi
|
||
|
||
if ! command -v parted &> /dev/null; then
|
||
packages_to_install+=("parted")
|
||
missing_packages="$missing_packages parted"
|
||
fi
|
||
|
||
if ! command -v wipefs &> /dev/null; then
|
||
packages_to_install+=("util-linux")
|
||
missing_packages="$missing_packages util-linux"
|
||
fi
|
||
|
||
# Check BTRFS / Verificar BTRFS
|
||
local btrfs_available=false
|
||
if command -v mkfs.btrfs &> /dev/null && command -v btrfs &> /dev/null; then
|
||
btrfs_available=true
|
||
show_message "$(get_text "btrfs_available")"
|
||
else
|
||
show_warning "$(get_text "btrfs_not_available")"
|
||
packages_to_install+=("btrfs-progs")
|
||
missing_packages="$missing_packages btrfs-progs"
|
||
fi
|
||
|
||
# Check ZFS / Verificar ZFS
|
||
local zfs_available=false
|
||
if command -v zpool &> /dev/null && command -v zfs &> /dev/null; then
|
||
zfs_available=true
|
||
show_message "$(get_text "zfs_available")"
|
||
else
|
||
show_warning "$(get_text "zfs_not_available")"
|
||
packages_to_install+=("zfsutils-linux")
|
||
missing_packages="$missing_packages zfsutils-linux"
|
||
fi
|
||
|
||
# Check mdadm (useful for cleanup) / Verificar mdadm (útil para limpieza)
|
||
if ! command -v mdadm &> /dev/null; then
|
||
packages_to_install+=("mdadm")
|
||
missing_packages="$missing_packages mdadm"
|
||
fi
|
||
|
||
# If no RAID tools available, we cannot continue / Si no hay herramientas RAID disponibles, no podemos continuar
|
||
if [ "$btrfs_available" = false ] && [ "$zfs_available" = false ]; then
|
||
show_error "$(get_text "no_raid_tools")"
|
||
show_message "$(get_text "will_install_packages")"
|
||
fi
|
||
|
||
# Install missing packages if necessary / Instalar paquetes faltantes si es necesario
|
||
if [ ${#packages_to_install[@]} -gt 0 ]; then
|
||
show_message "$(get_text "packages_to_install")$missing_packages"
|
||
|
||
# Check if ZFS is in the list / Verificar si ZFS está en la lista
|
||
local installing_zfs=false
|
||
for package in "${packages_to_install[@]}"; do
|
||
if [ "$package" = "zfsutils-linux" ]; then
|
||
installing_zfs=true
|
||
break
|
||
fi
|
||
done
|
||
|
||
if [ "$installing_zfs" = true ]; then
|
||
show_warning "$(get_text "zfs_install_warning")"
|
||
show_warning "$(get_text "installation_progress_shown")"
|
||
|
||
if ! confirm "$(get_text "continue_installation")"; then
|
||
show_message "$(get_text "installation_cancelled")"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
show_message "$(get_text "starting_installation")"
|
||
echo "----------------------------------------"
|
||
|
||
# Install packages with visible output / Instalar paquetes con output visible
|
||
for package in "${packages_to_install[@]}"; do
|
||
if [ "$package" = "zfsutils-linux" ]; then
|
||
show_message "$(get_text "installing_zfs")"
|
||
echo "$(get_text "zfs_progress")"
|
||
if sudo apt install -y "$package"; then
|
||
show_message "$(get_text "zfs_installed_successfully")"
|
||
else
|
||
show_error "$(get_text "error_installing_zfs")"
|
||
exit 1
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "🔄 Installing $package..."
|
||
if sudo apt install -y "$package" > /dev/null 2>&1; then
|
||
show_message "✅ $package installed successfully"
|
||
else
|
||
show_error "❌ Error installing $package"
|
||
exit 1
|
||
fi
|
||
else
|
||
show_message "🔄 Instalando $package..."
|
||
if sudo apt install -y "$package" > /dev/null 2>&1; then
|
||
show_message "✅ $package instalado exitosamente"
|
||
else
|
||
show_error "❌ Error instalando $package"
|
||
exit 1
|
||
fi
|
||
fi
|
||
fi
|
||
done
|
||
|
||
echo "----------------------------------------"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ All packages installed successfully"
|
||
else
|
||
show_message "✅ Todos los paquetes se instalaron correctamente"
|
||
fi
|
||
|
||
# Verificar que ZFS esté funcionando si se instaló
|
||
if [ "$installing_zfs" = true ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "🔄 Verifying ZFS functionality..."
|
||
else
|
||
show_message "🔄 Verificando funcionamiento de ZFS..."
|
||
fi
|
||
|
||
# Cargar módulo ZFS si no está cargado
|
||
if ! lsmod | grep -q "^zfs "; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Loading ZFS module..."
|
||
else
|
||
show_message "Cargando módulo ZFS..."
|
||
fi
|
||
sudo modprobe zfs
|
||
sleep 2
|
||
fi
|
||
|
||
# Verificar que los comandos funcionen
|
||
if zpool status > /dev/null 2>&1 && zfs version > /dev/null 2>&1; then
|
||
local zfs_version=$(zfs version | head -1 | awk '{print $2}')
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ ZFS working correctly (version: $zfs_version)"
|
||
else
|
||
show_message "✅ ZFS funcionando correctamente (versión: $zfs_version)"
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "❌ ZFS is not working correctly"
|
||
show_message "A system restart may be necessary"
|
||
if confirm "Do you want to continue anyway? (may fail)"; then
|
||
show_warning "Continuing with possibly non-functional ZFS..."
|
||
else
|
||
exit 1
|
||
fi
|
||
else
|
||
show_error "❌ ZFS no está funcionando correctamente"
|
||
show_message "Puede ser necesario reiniciar el sistema"
|
||
if confirm "¿Deseas continuar de todas formas? (puede fallar)"; then
|
||
show_warning "Continuando con ZFS posiblemente no funcional..."
|
||
else
|
||
exit 1
|
||
fi
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Breve pausa para que el usuario vea el resultado
|
||
sleep 1
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ All requirements are available"
|
||
else
|
||
show_message "✅ Todos los requisitos están disponibles"
|
||
fi
|
||
fi
|
||
|
||
# Mostrar resumen final de herramientas disponibles
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Available RAID tools:"
|
||
else
|
||
show_message "Herramientas RAID disponibles:"
|
||
fi
|
||
if command -v mkfs.btrfs &> /dev/null; then
|
||
local btrfs_version=$(btrfs --version 2>/dev/null | awk '{print $2}' || echo "desconocida")
|
||
echo " ✓ BTRFS (versión: $btrfs_version)"
|
||
fi
|
||
|
||
if command -v zpool &> /dev/null; then
|
||
local zfs_version=$(zfs version 2>/dev/null | head -1 | awk '{print $2}' || echo "desconocida")
|
||
echo " ✓ ZFS (versión: $zfs_version)"
|
||
fi
|
||
|
||
echo ""
|
||
}
|
||
|
||
# Function to detect all existing RAID configurations / Función para detectar todas las configuraciones RAID existentes
|
||
detect_existing_raid_configurations() {
|
||
show_title "$(get_text "detect_existing_raid")"
|
||
|
||
local zfs_found=false
|
||
local btrfs_found=false
|
||
local mdadm_found=false
|
||
local lvm_found=false
|
||
local any_raid_found=false
|
||
|
||
# 1. DETECTAR ZFS
|
||
if command -v zpool &> /dev/null; then
|
||
# Verificar que el módulo ZFS esté cargado
|
||
if ! lsmod | grep -q "^zfs "; then
|
||
sudo modprobe zfs 2>/dev/null || true
|
||
sleep 1
|
||
fi
|
||
|
||
local existing_pools=$(zpool list -H -o name 2>/dev/null)
|
||
if [ -n "$existing_pools" ]; then
|
||
zfs_found=true
|
||
any_raid_found=true
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "🔷 DETECTED ZFS POOLS:"
|
||
else
|
||
echo "🔷 POOLS ZFS DETECTADOS:"
|
||
fi
|
||
for pool in $existing_pools; do
|
||
local pool_health=$(zpool list -H -o health "$pool" 2>/dev/null)
|
||
local pool_size=$(zpool list -H -o size "$pool" 2>/dev/null)
|
||
local pool_used=$(zpool list -H -o allocated "$pool" 2>/dev/null)
|
||
local pool_free=$(zpool list -H -o free "$pool" 2>/dev/null)
|
||
|
||
echo " 📦 Pool: $pool"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 💚 Status: $pool_health"
|
||
echo " 📏 Size: $pool_size (Used: $pool_used, Free: $pool_free)"
|
||
else
|
||
echo " 💚 Estado: $pool_health"
|
||
echo " 📏 Tamaño: $pool_size (Usado: $pool_used, Libre: $pool_free)"
|
||
fi
|
||
|
||
# Mostrar datasets existentes
|
||
local datasets=$(zfs list -H -o name -r "$pool" 2>/dev/null | grep -v "^${pool}$")
|
||
if [ -n "$datasets" ]; then
|
||
local dataset_count=$(echo "$datasets" | wc -l)
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 📁 Datasets: $dataset_count"
|
||
else
|
||
echo " 📁 Datasets: $dataset_count"
|
||
fi
|
||
for dataset in $datasets; do
|
||
local used=$(zfs list -H -o used "$dataset" 2>/dev/null)
|
||
local mountpoint=$(zfs list -H -o mountpoint "$dataset" 2>/dev/null)
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " • $dataset (Used: $used, Mount: $mountpoint)"
|
||
else
|
||
echo " • $dataset (Usado: $used, Montaje: $mountpoint)"
|
||
fi
|
||
done
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 📁 No datasets (root pool only)"
|
||
else
|
||
echo " 📁 Sin datasets (solo pool raíz)"
|
||
fi
|
||
fi
|
||
|
||
# Mostrar dispositivos del pool
|
||
local pool_devices=$(zpool status "$pool" 2>/dev/null | grep -E "^\s+[a-z]" | awk '{print $1}' | grep -v "raidz\|mirror\|spare\|log\|cache\|replacing" | head -3)
|
||
if [ -n "$pool_devices" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 💿 Devices: $(echo $pool_devices | tr '\n' ' ' | sed 's/ *$//')..."
|
||
else
|
||
echo " 💿 Dispositivos: $(echo $pool_devices | tr '\n' ' ' | sed 's/ *$//')..."
|
||
fi
|
||
fi
|
||
echo ""
|
||
done
|
||
fi
|
||
fi
|
||
|
||
# 2. DETECTAR BTRFS
|
||
if command -v btrfs &> /dev/null; then
|
||
local btrfs_devices=()
|
||
local btrfs_info=()
|
||
|
||
# Buscar en todos los dispositivos
|
||
for device in $(lsblk -dpno NAME | grep -E "sd[a-z]|nvme"); do
|
||
if btrfs filesystem show "$device" 2>/dev/null | grep -q "uuid:"; then
|
||
local device_name=$(basename "$device")
|
||
local btrfs_uuid=$(btrfs filesystem show "$device" 2>/dev/null | grep "uuid:" | awk '{print $4}')
|
||
local size=$(lsblk -dpno SIZE "$device" | tr -d ' ')
|
||
local mount_point=$(mount | grep "$device" | awk '{print $3}' | head -1)
|
||
|
||
btrfs_devices+=("$device_name")
|
||
if [ -n "$mount_point" ]; then
|
||
btrfs_info+=("$device_name:$size:$mount_point:$btrfs_uuid")
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
btrfs_info+=("$device_name:$size:not_mounted:$btrfs_uuid")
|
||
else
|
||
btrfs_info+=("$device_name:$size:no_montado:$btrfs_uuid")
|
||
fi
|
||
fi
|
||
fi
|
||
done
|
||
|
||
if [ ${#btrfs_devices[@]} -gt 0 ]; then
|
||
btrfs_found=true
|
||
any_raid_found=true
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "🟠 DETECTED BTRFS FILESYSTEMS:"
|
||
else
|
||
echo "🟠 FILESYSTEMS BTRFS DETECTADOS:"
|
||
fi
|
||
for info in "${btrfs_info[@]}"; do
|
||
IFS=':' read -r device size mount_point uuid <<< "$info"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 📦 Device: $device"
|
||
echo " 📏 Size: $size"
|
||
echo " 📁 Mount: $mount_point"
|
||
echo " 🆔 UUID: $uuid"
|
||
else
|
||
echo " 📦 Dispositivo: $device"
|
||
echo " 📏 Tamaño: $size"
|
||
echo " 📁 Montaje: $mount_point"
|
||
echo " 🆔 UUID: $uuid"
|
||
fi
|
||
|
||
# Mostrar información adicional de BTRFS si está montado
|
||
if [ "$mount_point" != "no_montado" ] && [ "$mount_point" != "not_mounted" ]; then
|
||
local used=$(df -h "$mount_point" 2>/dev/null | tail -1 | awk '{print $3}')
|
||
local available=$(df -h "$mount_point" 2>/dev/null | tail -1 | awk '{print $4}')
|
||
if [ -n "$used" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 📊 Used: $used, Available: $available"
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 📊 Used: $used, Available: $available"
|
||
else
|
||
echo " 📊 Usado: $used, Disponible: $available"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Verificar subvolúmenes
|
||
local subvolumes=$(btrfs subvolume list "$mount_point" 2>/dev/null | wc -l)
|
||
if [ "$subvolumes" -gt 0 ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 📂 Subvolumes: $subvolumes"
|
||
else
|
||
echo " 📂 Subvolúmenes: $subvolumes"
|
||
fi
|
||
fi
|
||
fi
|
||
echo ""
|
||
done
|
||
fi
|
||
fi
|
||
|
||
# 3. DETECTAR MDADM (Linux Software RAID)
|
||
if command -v mdadm &> /dev/null; then
|
||
local mdadm_arrays=$(cat /proc/mdstat 2>/dev/null | grep "^md" | awk '{print $1}')
|
||
if [ -n "$mdadm_arrays" ]; then
|
||
mdadm_found=true
|
||
any_raid_found=true
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "🔴 DETECTED MDADM ARRAYS:"
|
||
else
|
||
echo "🔴 ARRAYS MDADM DETECTADOS:"
|
||
fi
|
||
for array in $mdadm_arrays; do
|
||
local array_info=$(mdadm --detail "/dev/$array" 2>/dev/null)
|
||
if [ -n "$array_info" ]; then
|
||
local raid_level=$(echo "$array_info" | grep "Raid Level" | awk '{print $4}')
|
||
local array_size=$(echo "$array_info" | grep "Array Size" | awk '{print $4$5}')
|
||
local state=$(echo "$array_info" | grep "State" | awk '{print $3}')
|
||
local num_devices=$(echo "$array_info" | grep "Total Devices" | awk '{print $4}')
|
||
|
||
echo " 📦 Array: /dev/$array"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 🔧 RAID Level: $raid_level"
|
||
echo " 📏 Size: $array_size"
|
||
echo " 💚 Status: $state"
|
||
echo " 💿 Devices: $num_devices"
|
||
else
|
||
echo " 🔧 Nivel RAID: $raid_level"
|
||
echo " 📏 Tamaño: $array_size"
|
||
echo " 💚 Estado: $state"
|
||
echo " 💿 Dispositivos: $num_devices"
|
||
fi
|
||
|
||
# Mostrar dispositivos del array
|
||
local devices=$(echo "$array_info" | grep "/dev/" | grep -v "failed\|spare" | awk '{print $7}' | head -3)
|
||
if [ -n "$devices" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 💿 Members: $(echo $devices | tr '\n' ' ' | sed 's/ *$//')..."
|
||
else
|
||
echo " 💿 Miembros: $(echo $devices | tr '\n' ' ' | sed 's/ *$//')..."
|
||
fi
|
||
fi
|
||
echo ""
|
||
fi
|
||
done
|
||
fi
|
||
fi
|
||
|
||
# 4. DETECTAR LVM
|
||
if command -v vgdisplay &> /dev/null; then
|
||
local volume_groups=$(vgdisplay 2>/dev/null | grep "VG Name" | awk '{print $3}')
|
||
if [ -n "$volume_groups" ]; then
|
||
lvm_found=true
|
||
any_raid_found=true
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "🟣 DETECTED LVM VOLUME GROUPS:"
|
||
else
|
||
echo "🟣 VOLUME GROUPS LVM DETECTADOS:"
|
||
fi
|
||
for vg in $volume_groups; do
|
||
local vg_info=$(vgdisplay "$vg" 2>/dev/null)
|
||
if [ -n "$vg_info" ]; then
|
||
local vg_size=$(echo "$vg_info" | grep "VG Size" | awk '{print $3$4}')
|
||
local vg_free=$(echo "$vg_info" | grep "Free PE" | awk '{print $5$6}')
|
||
local pv_count=$(echo "$vg_info" | grep "Cur PV" | awk '{print $3}')
|
||
local lv_count=$(echo "$vg_info" | grep "Cur LV" | awk '{print $3}')
|
||
|
||
echo " 📦 Volume Group: $vg"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 📏 Size: $vg_size"
|
||
echo " 💾 Free: $vg_free"
|
||
echo " 💿 Physical Volumes: $pv_count"
|
||
echo " 📁 Logical Volumes: $lv_count"
|
||
else
|
||
echo " 📏 Tamaño: $vg_size"
|
||
echo " 💾 Libre: $vg_free"
|
||
echo " 💿 Physical Volumes: $pv_count"
|
||
echo " 📁 Logical Volumes: $lv_count"
|
||
fi
|
||
|
||
# Mostrar logical volumes
|
||
local logical_volumes=$(lvdisplay "$vg" 2>/dev/null | grep "LV Name" | awk '{print $3}' | head -3)
|
||
if [ -n "$logical_volumes" ]; then
|
||
echo " 📂 LVs: $(echo $logical_volumes | tr '\n' ' ' | sed 's/ *$//')..."
|
||
fi
|
||
echo ""
|
||
fi
|
||
done
|
||
fi
|
||
fi
|
||
|
||
# SHOW SUMMARY AND OPTIONS / MOSTRAR RESUMEN Y OPCIONES
|
||
if [ "$any_raid_found" = true ]; then
|
||
echo "═══════════════════════════════════════════════════════════════════"
|
||
echo ""
|
||
echo "$(get_text "available_options")"
|
||
|
||
local option_number=1
|
||
|
||
if [ "$zfs_found" = true ]; then
|
||
echo " $option_number. $(get_text "manage_zfs_pools")"
|
||
zfs_option=$option_number
|
||
((option_number++))
|
||
|
||
echo " $option_number. $(get_text "delete_zfs_pools")"
|
||
zfs_delete_option=$option_number
|
||
((option_number++))
|
||
fi
|
||
|
||
if [ "$btrfs_found" = true ]; then
|
||
echo " $option_number. $(get_text "delete_btrfs_filesystems")"
|
||
btrfs_option=$option_number
|
||
((option_number++))
|
||
fi
|
||
|
||
if [ "$mdadm_found" = true ]; then
|
||
echo " $option_number. $(get_text "manage_mdadm_arrays")"
|
||
mdadm_option=$option_number
|
||
((option_number++))
|
||
fi
|
||
|
||
if [ "$lvm_found" = true ]; then
|
||
echo " $option_number. $(get_text "manage_lvm_groups")"
|
||
lvm_option=$option_number
|
||
((option_number++))
|
||
fi
|
||
|
||
echo " $option_number. $(get_text "continuing_new_raid")"
|
||
continue_option=$option_number
|
||
((option_number++))
|
||
|
||
echo " $option_number. $(get_text "exiting_script")"
|
||
exit_option=$option_number
|
||
echo ""
|
||
|
||
while true; do
|
||
read -p "👉 $(get_text "select_option") (1-$exit_option): " choice
|
||
|
||
if [ "$zfs_found" = true ] && [ "$choice" = "$zfs_option" ]; then
|
||
manage_existing_pools_datasets
|
||
return 1 # Indica que se gestionaron configuraciones existentes
|
||
elif [ "$zfs_found" = true ] && [ "$choice" = "$zfs_delete_option" ]; then
|
||
delete_existing_zfs_pools
|
||
return 1 # Indica que se eliminaron pools
|
||
elif [ "$btrfs_found" = true ] && [ "$choice" = "$btrfs_option" ]; then
|
||
local btrfs_devices_array=()
|
||
for info in "${btrfs_info[@]}"; do
|
||
IFS=':' read -r device size mount_point uuid <<< "$info"
|
||
btrfs_devices_array+=("$device")
|
||
done
|
||
delete_existing_btrfs "${btrfs_devices_array[@]}"
|
||
return 1 # Indica que se eliminaron filesystems
|
||
elif [ "$mdadm_found" = true ] && [ "$choice" = "$mdadm_option" ]; then
|
||
show_mdadm_details
|
||
echo ""
|
||
echo "$(get_text "mdadm_management_info")"
|
||
echo " • mdadm --detail /dev/mdX"
|
||
echo " • mdadm --stop /dev/mdX"
|
||
echo " • mdadm --manage /dev/mdX --fail /dev/sdX"
|
||
echo ""
|
||
if confirm "$(get_text "continue_detection")"; then
|
||
detect_existing_raid_configurations
|
||
return $?
|
||
else
|
||
return 1
|
||
fi
|
||
elif [ "$lvm_found" = true ] && [ "$choice" = "$lvm_option" ]; then
|
||
show_lvm_details
|
||
echo ""
|
||
echo "$(get_text "lvm_management_info")"
|
||
echo " • lvdisplay, vgdisplay, pvdisplay"
|
||
echo " • lvextend, lvreduce"
|
||
echo " • vgextend, vgreduce"
|
||
echo ""
|
||
if confirm "$(get_text "continue_detection")"; then
|
||
detect_existing_raid_configurations
|
||
return $?
|
||
else
|
||
return 1
|
||
fi
|
||
elif [ "$choice" = "$continue_option" ]; then
|
||
show_message "$(get_text "continuing_new_raid")..."
|
||
return 0 # Continúa con el flujo normal
|
||
elif [ "$choice" = "$exit_option" ]; then
|
||
show_message "$(get_text "exiting_script")..."
|
||
exit 0
|
||
else
|
||
echo "❌ $(get_text "invalid_option")."
|
||
fi
|
||
done
|
||
else
|
||
echo ""
|
||
echo "$(get_text "no_raid_detected")"
|
||
echo "$(get_text "system_ready_new_raid")"
|
||
echo ""
|
||
return 0 # Continue with normal configuration / Continúa con configuración normal
|
||
fi
|
||
}
|
||
|
||
# Función para mostrar detalles de arrays MDADM
|
||
show_mdadm_details() {
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "MDADM Array Details"
|
||
else
|
||
show_title "Detalles de Arrays MDADM"
|
||
fi
|
||
|
||
local mdadm_arrays=$(cat /proc/mdstat 2>/dev/null | grep "^md" | awk '{print $1}')
|
||
if [ -z "$mdadm_arrays" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "No MDADM arrays found"
|
||
else
|
||
show_warning "No se encontraron arrays MDADM"
|
||
fi
|
||
return 0
|
||
fi
|
||
|
||
for array in $mdadm_arrays; do
|
||
echo ""
|
||
echo "📦 ARRAY: /dev/$array"
|
||
echo "═══════════════════════════════════════════"
|
||
|
||
# Información detallada del array
|
||
local array_info=$(mdadm --detail "/dev/$array" 2>/dev/null)
|
||
if [ -n "$array_info" ]; then
|
||
echo "$array_info"
|
||
else
|
||
echo "❌ No se pudo obtener información detallada del array"
|
||
fi
|
||
|
||
echo ""
|
||
echo "📊 ESTADO EN /proc/mdstat:"
|
||
echo "═══════════════════════════════════════════"
|
||
cat /proc/mdstat | grep -A 3 "^$array"
|
||
echo ""
|
||
done
|
||
}
|
||
|
||
# Función para mostrar detalles de Volume Groups LVM
|
||
show_lvm_details() {
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "LVM Volume Group Details"
|
||
else
|
||
show_title "Detalles de Volume Groups LVM"
|
||
fi
|
||
|
||
local volume_groups=$(vgdisplay 2>/dev/null | grep "VG Name" | awk '{print $3}')
|
||
if [ -z "$volume_groups" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "No LVM Volume Groups found"
|
||
else
|
||
show_warning "No se encontraron Volume Groups LVM"
|
||
fi
|
||
return 0
|
||
fi
|
||
|
||
for vg in $volume_groups; do
|
||
echo ""
|
||
echo "📦 VOLUME GROUP: $vg"
|
||
echo "═══════════════════════════════════════════"
|
||
|
||
# Información detallada del VG
|
||
vgdisplay "$vg" 2>/dev/null
|
||
|
||
echo ""
|
||
echo "📁 LOGICAL VOLUMES EN $vg:"
|
||
echo "═══════════════════════════════════════════"
|
||
lvdisplay "$vg" 2>/dev/null
|
||
|
||
echo ""
|
||
echo "💿 PHYSICAL VOLUMES EN $vg:"
|
||
echo "═══════════════════════════════════════════"
|
||
pvdisplay 2>/dev/null | grep -A 10 "$vg" | head -15
|
||
echo ""
|
||
done
|
||
}
|
||
|
||
# Función para eliminar pools ZFS existentes
|
||
delete_existing_zfs_pools() {
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Delete Existing ZFS Pools"
|
||
else
|
||
show_title "Eliminación de Pools ZFS Existentes"
|
||
fi
|
||
|
||
local existing_pools=$(zpool list -H -o name 2>/dev/null)
|
||
if [ -z "$existing_pools" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "No ZFS pools found for deletion"
|
||
else
|
||
show_warning "No se encontraron pools ZFS para eliminar"
|
||
fi
|
||
return 0
|
||
fi
|
||
|
||
local pools_array=($existing_pools)
|
||
|
||
echo "⚠️ ADVERTENCIA: Esta operación eliminará completamente los pools seleccionados"
|
||
echo "🔥 TODOS LOS DATOS SE PERDERÁN PERMANENTEMENTE"
|
||
echo ""
|
||
|
||
echo "Pools ZFS disponibles para eliminar:"
|
||
for i in "${!pools_array[@]}"; do
|
||
local pool="${pools_array[$i]}"
|
||
local pool_health=$(zpool list -H -o health "$pool" 2>/dev/null)
|
||
local pool_size=$(zpool list -H -o size "$pool" 2>/dev/null)
|
||
local pool_used=$(zpool list -H -o allocated "$pool" 2>/dev/null)
|
||
|
||
echo " $((i+1)). $pool"
|
||
echo " 💚 Estado: $pool_health | 📊 Tamaño: $pool_size | 📈 Usado: $pool_used"
|
||
|
||
# Mostrar datasets
|
||
local datasets=$(zfs list -H -o name -r "$pool" 2>/dev/null | grep -v "^${pool}$")
|
||
if [ -n "$datasets" ]; then
|
||
local dataset_count=$(echo "$datasets" | wc -l)
|
||
echo " 📁 Datasets: $dataset_count"
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Deletion options:"
|
||
echo " • Pool number (e.g., 1, 2, 3)"
|
||
echo " • Multiple pools separated by spaces (e.g., 1 3 4)"
|
||
echo " • 'all' - Delete ALL pools (DANGEROUS!)"
|
||
echo " • 'cancel' - Cancel operation"
|
||
else
|
||
echo "Opciones de eliminación:"
|
||
echo " • Número del pool (ej: 1, 2, 3)"
|
||
echo " • Múltiples pools separados por espacios (ej: 1 3 4)"
|
||
echo " • 'all' - Eliminar TODOS los pools (¡PELIGROSO!)"
|
||
echo " • 'cancel' - Cancelar operación"
|
||
fi
|
||
echo ""
|
||
|
||
while true; do
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
read -p "👉 Pools to delete: " choice
|
||
else
|
||
read -p "👉 Pools a eliminar: " choice
|
||
fi
|
||
|
||
if [ "$choice" = "cancel" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Operation cancelled by user"
|
||
else
|
||
show_message "Operación cancelada por el usuario"
|
||
fi
|
||
return 0
|
||
elif [ "$choice" = "all" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ WARNING! You are going to delete ALL ZFS pools"
|
||
show_warning "⚠️ This includes: ${pools_array[*]}"
|
||
|
||
if confirm "Are you ABSOLUTELY SURE to delete ALL pools?"; then
|
||
for pool in "${pools_array[@]}"; do
|
||
echo ""
|
||
destroy_zfs_pool_safely "$pool"
|
||
done
|
||
show_message "✅ All pools have been processed"
|
||
return 0
|
||
else
|
||
show_message "Mass deletion cancelled"
|
||
continue
|
||
fi
|
||
else
|
||
show_warning "⚠️ ¡ADVERTENCIA! Vas a eliminar TODOS los pools ZFS"
|
||
show_warning "⚠️ Esto incluye: ${pools_array[*]}"
|
||
|
||
if confirm "¿Estás ABSOLUTAMENTE SEGURO de eliminar TODOS los pools?"; then
|
||
for pool in "${pools_array[@]}"; do
|
||
echo ""
|
||
destroy_zfs_pool_safely "$pool"
|
||
done
|
||
show_message "✅ Todos los pools han sido procesados"
|
||
return 0
|
||
else
|
||
show_message "Eliminación masiva cancelada"
|
||
continue
|
||
fi
|
||
fi
|
||
elif [[ "$choice" =~ ^[0-9\ ]+$ ]]; then
|
||
# Validar selecciones
|
||
local valid_selections=()
|
||
local invalid_found=false
|
||
|
||
for num in $choice; do
|
||
if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le ${#pools_array[@]} ]; then
|
||
local pool_index=$((num-1))
|
||
local pool_name="${pools_array[$pool_index]}"
|
||
if [[ ! " ${valid_selections[*]} " =~ " ${pool_name} " ]]; then
|
||
valid_selections+=("$pool_name")
|
||
fi
|
||
else
|
||
echo "❌ Selección inválida: $num (usa números del 1 al ${#pools_array[@]})"
|
||
invalid_found=true
|
||
fi
|
||
done
|
||
|
||
if [ "$invalid_found" = true ]; then
|
||
continue
|
||
fi
|
||
|
||
if [ ${#valid_selections[@]} -eq 0 ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "No valid pools selected"
|
||
else
|
||
show_error "No se seleccionaron pools válidos"
|
||
fi
|
||
continue
|
||
fi
|
||
|
||
# Mostrar resumen de pools a eliminar
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "Pools selected for deletion:"
|
||
else
|
||
show_warning "Pools seleccionados para eliminación:"
|
||
fi
|
||
for pool in "${valid_selections[@]}"; do
|
||
local pool_size=$(zpool list -H -o size "$pool" 2>/dev/null)
|
||
local pool_used=$(zpool list -H -o allocated "$pool" 2>/dev/null)
|
||
echo " 🗑️ $pool (Tamaño: $pool_size, Usado: $pool_used)"
|
||
done
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
if confirm "Do you confirm the deletion of these ${#valid_selections[@]} pools?"; then
|
||
for pool in "${valid_selections[@]}"; do
|
||
echo ""
|
||
destroy_zfs_pool_safely "$pool"
|
||
done
|
||
show_message "✅ Selected pools have been processed"
|
||
return 0
|
||
else
|
||
show_message "Deletion cancelled"
|
||
continue
|
||
fi
|
||
else
|
||
if confirm "¿Confirmas la eliminación de estos ${#valid_selections[@]} pools?"; then
|
||
for pool in "${valid_selections[@]}"; do
|
||
echo ""
|
||
destroy_zfs_pool_safely "$pool"
|
||
done
|
||
show_message "✅ Pools seleccionados han sido procesados"
|
||
return 0
|
||
else
|
||
show_message "Eliminación cancelada"
|
||
continue
|
||
fi
|
||
fi
|
||
else
|
||
echo "❌ Opción inválida. Usa números, 'all' o 'cancel'"
|
||
fi
|
||
done
|
||
}
|
||
|
||
# Función para detectar y gestionar filesystems BTRFS existentes
|
||
detect_and_manage_btrfs() {
|
||
if ! command -v btrfs &> /dev/null; then
|
||
return 0
|
||
fi
|
||
|
||
# Buscar filesystems BTRFS existentes
|
||
local btrfs_devices=()
|
||
local btrfs_info=()
|
||
|
||
# Buscar en todos los dispositivos
|
||
for device in $(lsblk -dpno NAME | grep -E "sd[a-z]|nvme"); do
|
||
if btrfs filesystem show "$device" 2>/dev/null | grep -q "uuid:"; then
|
||
local device_name=$(basename "$device")
|
||
local btrfs_uuid=$(btrfs filesystem show "$device" 2>/dev/null | grep "uuid:" | awk '{print $4}')
|
||
local size=$(lsblk -dpno SIZE "$device" | tr -d ' ')
|
||
local mount_point=$(mount | grep "$device" | awk '{print $3}' | head -1)
|
||
|
||
btrfs_devices+=("$device_name")
|
||
if [ -n "$mount_point" ]; then
|
||
btrfs_info+=("$device_name:$size:$mount_point:$btrfs_uuid")
|
||
else
|
||
btrfs_info+=("$device_name:$size:no_montado:$btrfs_uuid")
|
||
fi
|
||
fi
|
||
done
|
||
|
||
if [ ${#btrfs_devices[@]} -gt 0 ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Existing BTRFS Filesystems Detected"
|
||
else
|
||
show_title "Filesystems BTRFS Existentes Detectados"
|
||
fi
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "The following BTRFS filesystems were found:"
|
||
else
|
||
echo "Se encontraron los siguientes filesystems BTRFS:"
|
||
fi
|
||
|
||
for info in "${btrfs_info[@]}"; do
|
||
IFS=':' read -r device size mount_point uuid <<< "$info"
|
||
echo " 📦 Dispositivo: $device"
|
||
echo " 📏 Tamaño: $size"
|
||
echo " 📁 Montaje: $mount_point"
|
||
echo " 🆔 UUID: $uuid"
|
||
echo ""
|
||
done
|
||
|
||
echo "🛠️ OPCIONES PARA BTRFS:"
|
||
echo " 1. Eliminar filesystems BTRFS específicos"
|
||
echo " 2. Continuar sin modificar BTRFS"
|
||
echo ""
|
||
|
||
while true; do
|
||
read -p "👉 Selecciona una opción (1-2): " choice
|
||
case $choice in
|
||
1)
|
||
delete_existing_btrfs "${btrfs_devices[@]}"
|
||
break
|
||
;;
|
||
2)
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Continuing without modifying BTRFS filesystems..."
|
||
else
|
||
show_message "Continuando sin modificar filesystems BTRFS..."
|
||
fi
|
||
break
|
||
;;
|
||
*)
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "❌ Invalid option. Select 1 or 2."
|
||
else
|
||
echo "❌ Opción inválida. Selecciona 1 o 2."
|
||
fi
|
||
;;
|
||
esac
|
||
done
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
# Función para eliminar filesystems BTRFS existentes
|
||
delete_existing_btrfs() {
|
||
local btrfs_devices=("$@")
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Delete BTRFS Filesystems"
|
||
else
|
||
show_title "Eliminación de Filesystems BTRFS"
|
||
fi
|
||
|
||
echo "⚠️ ADVERTENCIA: Esta operación eliminará completamente los filesystems seleccionados"
|
||
echo "🔥 TODOS LOS DATOS SE PERDERÁN PERMANENTEMENTE"
|
||
echo ""
|
||
|
||
echo "Filesystems BTRFS disponibles para eliminar:"
|
||
for i in "${!btrfs_devices[@]}"; do
|
||
local device="${btrfs_devices[$i]}"
|
||
local size=$(lsblk -dpno SIZE "/dev/$device" | tr -d ' ')
|
||
local mount_point=$(mount | grep "/dev/$device" | awk '{print $3}' | head -1)
|
||
local uuid=$(btrfs filesystem show "/dev/$device" 2>/dev/null | grep "uuid:" | awk '{print $4}')
|
||
|
||
echo " $((i+1)). $device"
|
||
echo " 📏 Tamaño: $size"
|
||
if [ -n "$mount_point" ]; then
|
||
echo " 📁 Montado en: $mount_point"
|
||
else
|
||
echo " 📁 No montado"
|
||
fi
|
||
echo " 🆔 UUID: $uuid"
|
||
done
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Deletion options:"
|
||
echo " • Device number (e.g., 1, 2, 3)"
|
||
echo " • Multiple devices separated by spaces (e.g., 1 3)"
|
||
echo " • 'all' - Delete ALL BTRFS filesystems"
|
||
echo " • 'cancel' - Cancel operation"
|
||
else
|
||
echo "Opciones de eliminación:"
|
||
echo " • Número del dispositivo (ej: 1, 2, 3)"
|
||
echo " • Múltiples dispositivos separados por espacios (ej: 1 3)"
|
||
echo " • 'all' - Eliminar TODOS los filesystems BTRFS"
|
||
echo " • 'cancel' - Cancelar operación"
|
||
fi
|
||
echo ""
|
||
|
||
while true; do
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
read -p "👉 Filesystems to delete: " choice
|
||
else
|
||
read -p "👉 Filesystems a eliminar: " choice
|
||
fi
|
||
|
||
if [ "$choice" = "cancel" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Operation cancelled by user"
|
||
else
|
||
show_message "Operación cancelada por el usuario"
|
||
fi
|
||
return 0
|
||
elif [ "$choice" = "all" ]; then
|
||
show_warning "⚠️ ¡ADVERTENCIA! Vas a eliminar TODOS los filesystems BTRFS"
|
||
show_warning "⚠️ Esto incluye: ${btrfs_devices[*]}"
|
||
|
||
if confirm "¿Estás ABSOLUTAMENTE SEGURO de eliminar TODOS los filesystems BTRFS?"; then
|
||
# Agrupar dispositivos por UUID para manejar arrays multi-disco
|
||
local processed_uuids=()
|
||
|
||
for device in "${btrfs_devices[@]}"; do
|
||
local device_uuid=$(sudo btrfs filesystem show "/dev/$device" 2>/dev/null | grep "uuid:" | awk '{print $4}')
|
||
|
||
# Verificar si ya procesamos este UUID
|
||
if [[ ! " ${processed_uuids[*]} " =~ " ${device_uuid} " ]]; then
|
||
processed_uuids+=("$device_uuid")
|
||
|
||
# Obtener todos los dispositivos del array con este UUID
|
||
local array_devices=$(sudo btrfs filesystem show "/dev/$device" 2>/dev/null | grep "devid" | awk '{print $NF}' | sed 's|/dev/||')
|
||
|
||
echo ""
|
||
show_warning "🗑️ Eliminando array BTRFS (UUID: $device_uuid)"
|
||
show_message "📀 Dispositivos del array: $array_devices"
|
||
|
||
# Usar el primer dispositivo para la eliminación (que limpiará todo el array)
|
||
destroy_btrfs_array_safely "$device" "$device_uuid"
|
||
fi
|
||
done
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ All BTRFS filesystems have been processed"
|
||
else
|
||
show_message "✅ Todos los filesystems BTRFS han sido procesados"
|
||
fi
|
||
return 0
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Mass deletion cancelled"
|
||
else
|
||
show_message "Eliminación masiva cancelada"
|
||
fi
|
||
continue
|
||
fi
|
||
elif [[ "$choice" =~ ^[0-9\ ]+$ ]]; then
|
||
# Validar selecciones
|
||
local valid_selections=()
|
||
local invalid_found=false
|
||
|
||
for num in $choice; do
|
||
if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le ${#btrfs_devices[@]} ]; then
|
||
local device_index=$((num-1))
|
||
local device_name="${btrfs_devices[$device_index]}"
|
||
if [[ ! " ${valid_selections[*]} " =~ " ${device_name} " ]]; then
|
||
valid_selections+=("$device_name")
|
||
fi
|
||
else
|
||
echo "❌ Selección inválida: $num (usa números del 1 al ${#btrfs_devices[@]})"
|
||
invalid_found=true
|
||
fi
|
||
done
|
||
|
||
if [ "$invalid_found" = true ]; then
|
||
continue
|
||
fi
|
||
|
||
if [ ${#valid_selections[@]} -eq 0 ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "No valid devices selected"
|
||
else
|
||
show_error "No se seleccionaron dispositivos válidos"
|
||
fi
|
||
continue
|
||
fi
|
||
|
||
# Mostrar resumen de dispositivos a eliminar
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "BTRFS filesystems selected for deletion:"
|
||
else
|
||
show_warning "Filesystems BTRFS seleccionados para eliminación:"
|
||
fi
|
||
for device in "${valid_selections[@]}"; do
|
||
local size=$(lsblk -dpno SIZE "/dev/$device" | tr -d ' ')
|
||
echo " 🗑️ $device (Tamaño: $size)"
|
||
done
|
||
|
||
echo ""
|
||
if confirm "¿Confirmas la eliminación de estos ${#valid_selections[@]} filesystems?"; then
|
||
# Agrupar dispositivos por UUID para manejar arrays multi-disco
|
||
local processed_uuids=()
|
||
|
||
for device in "${valid_selections[@]}"; do
|
||
local device_uuid=$(sudo btrfs filesystem show "/dev/$device" 2>/dev/null | grep "uuid:" | awk '{print $4}')
|
||
|
||
# Verificar si ya procesamos este UUID
|
||
if [[ ! " ${processed_uuids[*]} " =~ " ${device_uuid} " ]]; then
|
||
processed_uuids+=("$device_uuid")
|
||
|
||
# Obtener información del array
|
||
local btrfs_info=$(sudo btrfs filesystem show "/dev/$device" 2>/dev/null)
|
||
local total_devices=$(echo "$btrfs_info" | grep "Total devices" | awk '{print $3}')
|
||
|
||
echo ""
|
||
if [ "$total_devices" -gt 1 ]; then
|
||
# Es un array multi-disco, usar la función de array
|
||
destroy_btrfs_array_safely "$device" "$device_uuid"
|
||
else
|
||
# Es un disco individual, usar la función tradicional
|
||
destroy_btrfs_safely "$device"
|
||
fi
|
||
fi
|
||
done
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ Selected BTRFS filesystems have been processed"
|
||
else
|
||
show_message "✅ Filesystems BTRFS seleccionados han sido procesados"
|
||
fi
|
||
return 0
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Deletion cancelled"
|
||
else
|
||
show_message "Eliminación cancelada"
|
||
fi
|
||
continue
|
||
fi
|
||
else
|
||
echo "❌ Opción inválida. Usa números, 'all' o 'cancel'"
|
||
fi
|
||
done
|
||
}
|
||
|
||
# Función para gestionar datasets de pools existentes
|
||
manage_existing_pools_datasets() {
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Dataset Management in Existing Pools"
|
||
else
|
||
show_title "Gestión de Datasets en Pools Existentes"
|
||
fi
|
||
|
||
local existing_pools=$(zpool list -H -o name 2>/dev/null)
|
||
local pools_array=($existing_pools)
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Select the pool where you want to manage datasets:"
|
||
else
|
||
echo "Selecciona el pool donde quieres gestionar datasets:"
|
||
fi
|
||
for i in "${!pools_array[@]}"; do
|
||
local pool="${pools_array[$i]}"
|
||
local pool_health=$(zpool list -H -o health "$pool" 2>/dev/null)
|
||
local pool_free=$(zpool list -H -o free "$pool" 2>/dev/null)
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " $((i+1)). $pool (Health: $pool_health, Free: $pool_free)"
|
||
else
|
||
echo " $((i+1)). $pool (Estado: $pool_health, Libre: $pool_free)"
|
||
fi
|
||
done
|
||
echo ""
|
||
|
||
while true; do
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
read -p "👉 Select pool (1-${#pools_array[@]}): " pool_choice
|
||
else
|
||
read -p "👉 Selecciona pool (1-${#pools_array[@]}): " pool_choice
|
||
fi
|
||
if [[ "$pool_choice" =~ ^[0-9]+$ ]] && [ "$pool_choice" -ge 1 ] && [ "$pool_choice" -le ${#pools_array[@]} ]; then
|
||
local selected_pool="${pools_array[$((pool_choice-1))]}"
|
||
create_datasets_in_pool "$selected_pool"
|
||
break
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "❌ Invalid selection. Use numbers from 1 to ${#pools_array[@]}."
|
||
else
|
||
echo "❌ Selección inválida. Usa números del 1 al ${#pools_array[@]}."
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Preguntar si quiere gestionar otro pool
|
||
if [ ${#pools_array[@]} -gt 1 ]; then
|
||
if confirm "¿Deseas gestionar datasets en otro pool?"; then
|
||
manage_existing_pools_datasets
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# Función para eliminar datasets de un pool específico
|
||
delete_dataset_from_pool() {
|
||
local pool_name="$1"
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Delete Datasets in Pool '$pool_name'"
|
||
else
|
||
show_title "Eliminación de Datasets en Pool '$pool_name'"
|
||
fi
|
||
|
||
# Obtener datasets existentes (excluyendo el pool raíz)
|
||
local existing_datasets=$(zfs list -H -o name -r "$pool_name" 2>/dev/null | grep -v "^${pool_name}$")
|
||
|
||
if [ -z "$existing_datasets" ]; then
|
||
show_warning "No hay datasets para eliminar en el pool '$pool_name'"
|
||
echo "Solo existe el pool raíz que no puede ser eliminado desde aquí."
|
||
return 0
|
||
fi
|
||
|
||
# Convertir a array para manejo más fácil
|
||
local datasets_array=()
|
||
while IFS= read -r dataset; do
|
||
datasets_array+=("$dataset")
|
||
done <<< "$existing_datasets"
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "⚠️ WARNING: Dataset deletion is PERMANENT"
|
||
echo "🔥 ALL DATA from the selected dataset will be lost"
|
||
else
|
||
echo "⚠️ ADVERTENCIA: La eliminación de datasets es PERMANENTE"
|
||
echo "🔥 TODOS LOS DATOS del dataset seleccionado se perderán"
|
||
fi
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "📁 Datasets available for deletion:"
|
||
else
|
||
echo "📁 Datasets disponibles para eliminar:"
|
||
fi
|
||
|
||
for i in "${!datasets_array[@]}"; do
|
||
local dataset="${datasets_array[$i]}"
|
||
local used=$(zfs list -H -o used "$dataset" 2>/dev/null)
|
||
local mountpoint=$(zfs list -H -o mountpoint "$dataset" 2>/dev/null)
|
||
local compression=$(zfs get -H -o value compression "$dataset" 2>/dev/null)
|
||
|
||
echo " $((i+1)). $dataset"
|
||
echo " 📊 Usado: $used | 📁 Montaje: $mountpoint | 🗜️ Compresión: $compression"
|
||
|
||
# Mostrar snapshots si existen
|
||
local snapshots=$(zfs list -t snapshot -H -o name "$dataset" 2>/dev/null | wc -l)
|
||
if [ "$snapshots" -gt 0 ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 📸 Snapshots: $snapshots (will also be deleted)"
|
||
else
|
||
echo " 📸 Snapshots: $snapshots (también serán eliminados)"
|
||
fi
|
||
fi
|
||
echo ""
|
||
done
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Deletion options:"
|
||
echo " • Dataset number (e.g., 1, 2, 3)"
|
||
echo " • Multiple datasets separated by spaces (e.g., 1 3 4)"
|
||
echo " • 'all' - Delete ALL datasets (DANGEROUS!)"
|
||
echo " • 'cancel' - Cancel operation"
|
||
else
|
||
echo "Opciones de eliminación:"
|
||
echo " • Número del dataset (ej: 1, 2, 3)"
|
||
echo " • Múltiples datasets separados por espacios (ej: 1 3 4)"
|
||
echo " • 'all' - Eliminar TODOS los datasets (¡PELIGROSO!)"
|
||
echo " • 'cancel' - Cancelar operación"
|
||
fi
|
||
echo ""
|
||
|
||
while true; do
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
read -p "👉 Datasets to delete: " choice
|
||
else
|
||
read -p "👉 Datasets a eliminar: " choice
|
||
fi
|
||
|
||
if [ "$choice" = "cancel" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Deletion cancelled by user"
|
||
else
|
||
show_message "Eliminación cancelada por el usuario"
|
||
fi
|
||
return 0
|
||
elif [ "$choice" = "all" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ WARNING! You are going to delete ALL datasets"
|
||
show_warning "⚠️ This includes: ${datasets_array[*]}"
|
||
echo ""
|
||
echo "🔥 THIS WILL PERMANENTLY DELETE:"
|
||
for dataset in "${datasets_array[@]}"; do
|
||
local used=$(zfs list -H -o used "$dataset" 2>/dev/null)
|
||
echo " • $dataset (Used: $used)"
|
||
done
|
||
echo ""
|
||
|
||
if confirm "Are you ABSOLUTELY SURE to delete ALL datasets?"; then
|
||
# Eliminar en orden inverso para manejar dependencias
|
||
for ((i=${#datasets_array[@]}-1; i>=0; i--)); do
|
||
local dataset="${datasets_array[$i]}"
|
||
echo ""
|
||
delete_dataset_safely "$dataset"
|
||
done
|
||
show_message "✅ All datasets have been processed"
|
||
return 0
|
||
else
|
||
show_message "Mass deletion cancelled"
|
||
continue
|
||
fi
|
||
else
|
||
show_warning "⚠️ ¡ADVERTENCIA! Vas a eliminar TODOS los datasets"
|
||
show_warning "⚠️ Esto incluye: ${datasets_array[*]}"
|
||
echo ""
|
||
echo "🔥 ESTO ELIMINARÁ PERMANENTEMENTE:"
|
||
for dataset in "${datasets_array[@]}"; do
|
||
local used=$(zfs list -H -o used "$dataset" 2>/dev/null)
|
||
echo " • $dataset (Usado: $used)"
|
||
done
|
||
echo ""
|
||
|
||
if confirm "¿Estás ABSOLUTAMENTE SEGURO de eliminar TODOS los datasets?"; then
|
||
# Eliminar en orden inverso para manejar dependencias
|
||
for ((i=${#datasets_array[@]}-1; i>=0; i--)); do
|
||
local dataset="${datasets_array[$i]}"
|
||
echo ""
|
||
delete_dataset_safely "$dataset"
|
||
done
|
||
show_message "✅ Todos los datasets han sido procesados"
|
||
return 0
|
||
else
|
||
show_message "Eliminación masiva cancelada"
|
||
continue
|
||
fi
|
||
fi
|
||
elif [[ "$choice" =~ ^[0-9\ ]+$ ]]; then
|
||
# Validar selecciones
|
||
local valid_selections=()
|
||
local invalid_found=false
|
||
|
||
for num in $choice; do
|
||
if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le ${#datasets_array[@]} ]; then
|
||
local dataset_index=$((num-1))
|
||
local dataset_name="${datasets_array[$dataset_index]}"
|
||
if [[ ! " ${valid_selections[*]} " =~ " ${dataset_name} " ]]; then
|
||
valid_selections+=("$dataset_name")
|
||
fi
|
||
else
|
||
echo "❌ Selección inválida: $num (usa números del 1 al ${#datasets_array[@]})"
|
||
invalid_found=true
|
||
fi
|
||
done
|
||
|
||
if [ "$invalid_found" = true ]; then
|
||
continue
|
||
fi
|
||
|
||
if [ ${#valid_selections[@]} -eq 0 ]; then
|
||
show_error "No se seleccionaron datasets válidos"
|
||
continue
|
||
fi
|
||
|
||
# Mostrar resumen de datasets a eliminar
|
||
echo ""
|
||
show_warning "Datasets seleccionados para eliminación:"
|
||
for dataset in "${valid_selections[@]}"; do
|
||
local used=$(zfs list -H -o used "$dataset" 2>/dev/null)
|
||
local snapshots=$(zfs list -t snapshot -H -o name "$dataset" 2>/dev/null | wc -l)
|
||
echo " 🗑️ $dataset (Usado: $used)"
|
||
if [ "$snapshots" -gt 0 ]; then
|
||
echo " 📸 Incluye $snapshots snapshots"
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
if confirm "¿Confirmas la eliminación de estos ${#valid_selections[@]} datasets?"; then
|
||
# Ordenar datasets para eliminar los más profundos primero
|
||
# (importante para evitar errores de dependencias)
|
||
local sorted_selections=($(printf '%s\n' "${valid_selections[@]}" | sort -r))
|
||
|
||
for dataset in "${sorted_selections[@]}"; do
|
||
echo ""
|
||
delete_dataset_safely "$dataset"
|
||
done
|
||
show_message "✅ Datasets seleccionados han sido procesados"
|
||
return 0
|
||
else
|
||
show_message "Eliminación cancelada"
|
||
continue
|
||
fi
|
||
else
|
||
echo "❌ Opción inválida. Usa números, 'all' o 'cancel'"
|
||
fi
|
||
done
|
||
}
|
||
|
||
# Función para eliminar un dataset de forma segura
|
||
delete_dataset_safely() {
|
||
local dataset="$1"
|
||
|
||
if [ -z "$dataset" ]; then
|
||
show_error "Nombre de dataset no especificado"
|
||
return 1
|
||
fi
|
||
|
||
# Verificar que el dataset existe
|
||
if ! zfs list "$dataset" >/dev/null 2>&1; then
|
||
show_warning "Dataset '$dataset' no encontrado"
|
||
return 0
|
||
fi
|
||
|
||
show_warning "🗑️ Eliminando dataset: '$dataset'"
|
||
|
||
# Mostrar información del dataset antes de eliminar
|
||
local used=$(zfs list -H -o used "$dataset" 2>/dev/null)
|
||
local mountpoint=$(zfs list -H -o mountpoint "$dataset" 2>/dev/null)
|
||
local compression=$(zfs get -H -o value compression "$dataset" 2>/dev/null)
|
||
|
||
echo " 📊 Datos a eliminar: $used"
|
||
echo " 📁 Punto de montaje: $mountpoint"
|
||
echo " 🗜️ Compresión: $compression"
|
||
|
||
# Verificar y mostrar snapshots
|
||
local snapshots=$(zfs list -t snapshot -H -o name "$dataset" 2>/dev/null)
|
||
if [ -n "$snapshots" ]; then
|
||
local snapshot_count=$(echo "$snapshots" | wc -l)
|
||
echo " 📸 Snapshots a eliminar: $snapshot_count"
|
||
for snapshot in $snapshots; do
|
||
local snap_used=$(zfs list -t snapshot -H -o used "$snapshot" 2>/dev/null)
|
||
echo " • $snapshot (Usado: $snap_used)"
|
||
done
|
||
fi
|
||
|
||
# Verificar si tiene datasets hijos
|
||
local child_datasets=$(zfs list -H -o name -r "$dataset" 2>/dev/null | grep -v "^${dataset}$")
|
||
if [ -n "$child_datasets" ]; then
|
||
echo " 📂 Datasets hijos que también serán eliminados:"
|
||
for child in $child_datasets; do
|
||
local child_used=$(zfs list -H -o used "$child" 2>/dev/null)
|
||
echo " • $child (Usado: $child_used)"
|
||
done
|
||
fi
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ THIS ACTION WILL PERMANENTLY DELETE:"
|
||
show_warning " • The dataset '$dataset' and all its data"
|
||
if [ -n "$snapshots" ]; then
|
||
show_warning " • All dataset snapshots"
|
||
fi
|
||
if [ -n "$child_datasets" ]; then
|
||
show_warning " • All child datasets and their data"
|
||
fi
|
||
else
|
||
show_warning "⚠️ ESTA ACCIÓN ELIMINARÁ PERMANENTEMENTE:"
|
||
show_warning " • El dataset '$dataset' y todos sus datos"
|
||
if [ -n "$snapshots" ]; then
|
||
show_warning " • Todos los snapshots del dataset"
|
||
fi
|
||
if [ -n "$child_datasets" ]; then
|
||
show_warning " • Todos los datasets hijos y sus datos"
|
||
fi
|
||
fi
|
||
echo ""
|
||
|
||
# Proceder con la eliminación
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "🔄 Deleting dataset '$dataset'..."
|
||
else
|
||
show_message "🔄 Eliminando dataset '$dataset'..."
|
||
fi
|
||
|
||
# 1. Desmontar el dataset si está montado
|
||
if [ "$mountpoint" != "none" ] && [ "$mountpoint" != "-" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Unmounting dataset..."
|
||
else
|
||
show_message "Desmontando dataset..."
|
||
fi
|
||
sudo zfs unmount "$dataset" 2>/dev/null || true
|
||
fi
|
||
|
||
# 2. Eliminar el dataset con todos sus snapshots y descendientes
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Destroying dataset and dependencies..."
|
||
else
|
||
show_message "Destruyendo dataset y dependencias..."
|
||
fi
|
||
if sudo zfs destroy -r "$dataset" 2>/dev/null; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ Dataset '$dataset' deleted successfully"
|
||
else
|
||
show_message "✅ Dataset '$dataset' eliminado exitosamente"
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ Standard attempt failed, trying forced deletion..."
|
||
|
||
# Intentar eliminación forzada
|
||
if sudo zfs destroy -f -r "$dataset" 2>/dev/null; then
|
||
show_message "✅ Dataset '$dataset' forcibly deleted"
|
||
else
|
||
show_error "❌ Could not delete dataset '$dataset'"
|
||
show_error " Possible causes:"
|
||
show_error " • Dataset in use by some process"
|
||
show_error " • Snapshot or clone dependencies"
|
||
show_error " • Insufficient permissions"
|
||
return 1
|
||
fi
|
||
else
|
||
show_warning "⚠️ Intento estándar falló, intentando eliminación forzada..."
|
||
|
||
# Intentar eliminación forzada
|
||
if sudo zfs destroy -f -r "$dataset" 2>/dev/null; then
|
||
show_message "✅ Dataset '$dataset' eliminado forzadamente"
|
||
else
|
||
show_error "❌ No se pudo eliminar el dataset '$dataset'"
|
||
show_error " Posibles causas:"
|
||
show_error " • Dataset en uso por algún proceso"
|
||
show_error " • Dependencias de snapshots o clones"
|
||
show_error " • Permisos insuficientes"
|
||
return 1
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
# Función para crear datasets en un pool específico (reutilizable)
|
||
create_datasets_in_pool() {
|
||
local pool_name="$1"
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Dataset Management in Pool '$pool_name'"
|
||
else
|
||
show_title "Gestión de Datasets en Pool '$pool_name'"
|
||
fi
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 DATASET INFORMATION:"
|
||
else
|
||
echo "💡 INFORMACIÓN SOBRE DATASETS:"
|
||
fi
|
||
echo " Los datasets son subdivisiones lógicas dentro del pool ZFS."
|
||
echo " Beneficios:"
|
||
echo " • Organización de datos (data, backups, media, etc.)"
|
||
echo " • Cuotas de espacio independientes"
|
||
echo " • Snapshots y backups granulares"
|
||
echo " • Diferentes configuraciones de compresión"
|
||
echo " • Puntos de montaje personalizados"
|
||
echo ""
|
||
echo " Ejemplo: $pool_name/data, $pool_name/backups, $pool_name/media"
|
||
echo ""
|
||
|
||
# Mostrar datasets existentes
|
||
local existing_datasets=$(zfs list -H -o name -r "$pool_name" 2>/dev/null | grep -v "^${pool_name}$")
|
||
if [ -n "$existing_datasets" ]; then
|
||
echo "📁 Datasets existentes en '$pool_name':"
|
||
for dataset in $existing_datasets; do
|
||
local used=$(zfs list -H -o used "$dataset" 2>/dev/null)
|
||
local mountpoint=$(zfs list -H -o mountpoint "$dataset" 2>/dev/null)
|
||
local compression=$(zfs get -H -o value compression "$dataset" 2>/dev/null)
|
||
echo " ✓ $dataset"
|
||
echo " 📊 Usado: $used | 📁 Montaje: $mountpoint | 🗜️ Compresión: $compression"
|
||
done
|
||
echo ""
|
||
fi
|
||
|
||
echo "📋 DATASETS COMUNES SUGERIDOS:"
|
||
echo " 1. data - Datos principales y documentos"
|
||
echo " 2. media - Videos, fotos, música"
|
||
echo " 3. backups - Copias de seguridad"
|
||
echo " 4. temp - Archivos temporales"
|
||
echo " 5. vm - Máquinas virtuales"
|
||
echo " 6. docker - Contenedores Docker"
|
||
echo " 7. homes - Directorios de usuario"
|
||
echo ""
|
||
|
||
local datasets_created=()
|
||
|
||
while true; do
|
||
echo "Opciones:"
|
||
echo " • Nombre del dataset (ej: data, media, backups)"
|
||
echo " • 'suggested' - Crear datasets comunes (data, media, backups)"
|
||
echo " • 'list' - Mostrar datasets actuales"
|
||
echo " • 'delete' - Eliminar dataset existente"
|
||
echo " • 'done' - Finalizar gestión de datasets"
|
||
echo ""
|
||
|
||
read -p "👉 Dataset a crear/gestionar: " dataset_choice
|
||
|
||
if [ "$dataset_choice" = "done" ]; then
|
||
break
|
||
elif [ "$dataset_choice" = "list" ]; then
|
||
# Mostrar datasets actuales
|
||
local current_datasets=$(zfs list -H -o name -r "$pool_name" 2>/dev/null | grep -v "^${pool_name}$")
|
||
if [ -n "$current_datasets" ]; then
|
||
echo ""
|
||
echo "📁 Datasets actuales en '$pool_name':"
|
||
for dataset in $current_datasets; do
|
||
local used=$(zfs list -H -o used "$dataset" 2>/dev/null)
|
||
local avail=$(zfs list -H -o avail "$dataset" 2>/dev/null)
|
||
local mountpoint=$(zfs list -H -o mountpoint "$dataset" 2>/dev/null)
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " ✓ $dataset (Used: $used, Available: $avail, Mount: $mountpoint)"
|
||
else
|
||
echo " ✓ $dataset (Usado: $used, Disponible: $avail, Montaje: $mountpoint)"
|
||
fi
|
||
done
|
||
echo ""
|
||
else
|
||
echo " (no hay datasets creados aún)"
|
||
echo ""
|
||
fi
|
||
elif [ "$dataset_choice" = "delete" ]; then
|
||
delete_dataset_from_pool "$pool_name"
|
||
elif [ "$dataset_choice" = "suggested" ]; then
|
||
local suggested_datasets=("data" "media" "backups")
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Creating suggested datasets: ${suggested_datasets[*]}"
|
||
else
|
||
show_message "Creando datasets sugeridos: ${suggested_datasets[*]}"
|
||
fi
|
||
|
||
for dataset in "${suggested_datasets[@]}"; do
|
||
# Verificar si ya existe
|
||
if zfs list "$pool_name/$dataset" >/dev/null 2>&1; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "ℹ️ Dataset '$pool_name/$dataset' already exists"
|
||
else
|
||
show_message "ℹ️ Dataset '$pool_name/$dataset' ya existe"
|
||
fi
|
||
continue
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Creating dataset: $pool_name/$dataset"
|
||
else
|
||
show_message "Creando dataset: $pool_name/$dataset"
|
||
fi
|
||
|
||
if sudo zfs create "$pool_name/$dataset"; then
|
||
datasets_created+=("$dataset")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ Dataset '$pool_name/$dataset' created successfully"
|
||
else
|
||
show_message "✅ Dataset '$pool_name/$dataset' creado exitosamente"
|
||
fi
|
||
|
||
# Configurar montaje automático
|
||
sudo zfs set mountpoint="/$pool_name/$dataset" "$pool_name/$dataset"
|
||
|
||
# Configuraciones específicas por tipo
|
||
case $dataset in
|
||
"media")
|
||
# Optimizar para archivos grandes
|
||
sudo zfs set recordsize=1M "$pool_name/$dataset"
|
||
sudo zfs set compression=lz4 "$pool_name/$dataset"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message " 📺 Optimized for multimedia files"
|
||
else
|
||
show_message " 📺 Optimizado para archivos multimedia"
|
||
fi
|
||
;;
|
||
"backups")
|
||
# Máxima compresión para backups
|
||
sudo zfs set compression=gzip "$pool_name/$dataset"
|
||
sudo zfs set dedup=on "$pool_name/$dataset" 2>/dev/null || true
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message " 💾 Optimized for backups (high compression)"
|
||
else
|
||
show_message " 💾 Optimizado para backups (alta compresión)"
|
||
fi
|
||
;;
|
||
"data")
|
||
# Balance entre compresión y rendimiento
|
||
sudo zfs set compression=lz4 "$pool_name/$dataset"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message " 📁 Optimized for general data"
|
||
else
|
||
show_message " 📁 Optimizado para datos generales"
|
||
fi
|
||
;;
|
||
esac
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "❌ Error creating dataset '$pool_name/$dataset'"
|
||
else
|
||
show_error "❌ Error creando dataset '$pool_name/$dataset'"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
elif [ -n "$dataset_choice" ] && [[ "$dataset_choice" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
||
# Crear dataset individual
|
||
if zfs list "$pool_name/$dataset_choice" >/dev/null 2>&1; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "ℹ️ Dataset '$pool_name/$dataset_choice' already exists"
|
||
else
|
||
show_message "ℹ️ Dataset '$pool_name/$dataset_choice' ya existe"
|
||
fi
|
||
continue
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Creating dataset: $pool_name/$dataset_choice"
|
||
else
|
||
show_message "Creando dataset: $pool_name/$dataset_choice"
|
||
fi
|
||
|
||
if sudo zfs create "$pool_name/$dataset_choice"; then
|
||
datasets_created+=("$dataset_choice")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ Dataset '$pool_name/$dataset_choice' created successfully"
|
||
else
|
||
show_message "✅ Dataset '$pool_name/$dataset_choice' creado exitosamente"
|
||
fi
|
||
|
||
# Configurar montaje
|
||
sudo zfs set mountpoint="/$pool_name/$dataset_choice" "$pool_name/$dataset_choice"
|
||
|
||
# Preguntar por configuraciones específicas
|
||
echo ""
|
||
echo "⚙️ CONFIGURACIONES OPCIONALES para '$dataset_choice':"
|
||
|
||
if confirm "¿Configurar compresión? (recomendado)"; then
|
||
echo "Tipos de compresión:"
|
||
echo "1. lz4 - Rápida, buen balance (recomendado)"
|
||
echo "2. gzip - Alta compresión, más lenta"
|
||
echo "3. off - Sin compresión"
|
||
|
||
read -p "Selecciona (1-3) [1]: " compression_choice
|
||
compression_choice=${compression_choice:-1}
|
||
|
||
case $compression_choice in
|
||
1) sudo zfs set compression=lz4 "$pool_name/$dataset_choice";;
|
||
2) sudo zfs set compression=gzip "$pool_name/$dataset_choice";;
|
||
3) sudo zfs set compression=off "$pool_name/$dataset_choice";;
|
||
esac
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message " 🗜️ Compression configured"
|
||
else
|
||
show_message " 🗜️ Compresión configurada"
|
||
fi
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
if confirm "Set space quota?"; then
|
||
read -p "Quota in GB (e.g., 100): " quota_gb
|
||
if [[ "$quota_gb" =~ ^[0-9]+$ ]] && [ "$quota_gb" -gt 0 ]; then
|
||
sudo zfs set quota="${quota_gb}G" "$pool_name/$dataset_choice"
|
||
show_message " 📏 Quota set: ${quota_gb}GB"
|
||
fi
|
||
fi
|
||
else
|
||
if confirm "¿Establecer cuota de espacio?"; then
|
||
read -p "Cuota en GB (ej: 100): " quota_gb
|
||
if [[ "$quota_gb" =~ ^[0-9]+$ ]] && [ "$quota_gb" -gt 0 ]; then
|
||
sudo zfs set quota="${quota_gb}G" "$pool_name/$dataset_choice"
|
||
show_message " 📏 Cuota establecida: ${quota_gb}GB"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "❌ Error creating dataset '$pool_name/$dataset_choice'"
|
||
else
|
||
show_error "❌ Error creando dataset '$pool_name/$dataset_choice'"
|
||
fi
|
||
fi
|
||
|
||
else
|
||
if [ -z "$dataset_choice" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "❌ Dataset name cannot be empty"
|
||
else
|
||
show_error "❌ El nombre del dataset no puede estar vacío"
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "❌ Invalid name. Use only letters, numbers, hyphens and underscores"
|
||
else
|
||
show_error "❌ Nombre inválido. Usa solo letras, números, guiones y guiones bajos"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
done
|
||
|
||
# Mostrar resumen de datasets creados en esta sesión
|
||
if [ ${#datasets_created[@]} -gt 0 ]; then
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "📊 SUMMARY OF DATASETS CREATED IN THIS SESSION:"
|
||
else
|
||
show_message "📊 RESUMEN DE DATASETS CREADOS EN ESTA SESIÓN:"
|
||
fi
|
||
for dataset in "${datasets_created[@]}"; do
|
||
local mountpoint=$(zfs get -H -o value mountpoint "$pool_name/$dataset" 2>/dev/null)
|
||
local compression=$(zfs get -H -o value compression "$pool_name/$dataset" 2>/dev/null)
|
||
local quota=$(zfs get -H -o value quota "$pool_name/$dataset" 2>/dev/null)
|
||
|
||
echo " ✅ $pool_name/$dataset"
|
||
echo " 📁 Montaje: $mountpoint"
|
||
echo " 🗜️ Compresión: $compression"
|
||
if [ "$quota" != "none" ]; then
|
||
echo " 📏 Cuota: $quota"
|
||
fi
|
||
echo ""
|
||
done
|
||
fi
|
||
}
|
||
|
||
# Función para verificar si un disco está en uso por RAID
|
||
check_disk_raid_status() {
|
||
local disk="$1"
|
||
local raid_info=""
|
||
|
||
# Verificar BTRFS - Mejorado para detectar arrays multi-disco
|
||
if command -v btrfs &> /dev/null; then
|
||
# Primero verificar si el disco tiene un filesystem BTRFS
|
||
if sudo btrfs filesystem show "/dev/$disk" 2>/dev/null | grep -q "uuid:"; then
|
||
local btrfs_uuid=$(sudo btrfs filesystem show "/dev/$disk" 2>/dev/null | grep "uuid:" | awk '{print $4}')
|
||
local btrfs_label=$(sudo btrfs filesystem show "/dev/$disk" 2>/dev/null | grep "Label:" | awk '{print $2}')
|
||
|
||
# Obtener información detallada del array BTRFS
|
||
local btrfs_info=$(sudo btrfs filesystem show "/dev/$disk" 2>/dev/null)
|
||
local total_devices=$(echo "$btrfs_info" | grep "Total devices" | awk '{print $3}')
|
||
local device_list=$(echo "$btrfs_info" | grep "devid" | awk '{print $NF}' | sed 's|/dev/||' | tr '\n' ',' | sed 's/,$//')
|
||
|
||
# Obtener el punto de montaje si existe
|
||
local mount_point=$(mount | grep "/dev/$disk" | awk '{print $3}' | head -1)
|
||
|
||
# Intentar obtener el tipo de RAID si está montado
|
||
local raid_profile=""
|
||
if [ -n "$mount_point" ]; then
|
||
raid_profile=$(sudo btrfs filesystem usage "$mount_point" 2>/dev/null | grep "Data," | head -1 | awk '{print $1}' | cut -d',' -f2 | cut -d':' -f1)
|
||
if [ -z "$raid_profile" ]; then
|
||
raid_profile="single"
|
||
fi
|
||
fi
|
||
|
||
# Construir información del RAID
|
||
if [ "$total_devices" -gt 1 ]; then
|
||
if [ -n "$mount_point" ]; then
|
||
raid_info="BTRFS RAID ($raid_profile, $total_devices discos: $device_list) - Montado en: $mount_point"
|
||
else
|
||
raid_info="BTRFS RAID ($total_devices discos: $device_list)"
|
||
fi
|
||
else
|
||
if [ -n "$mount_point" ]; then
|
||
raid_info="BTRFS (Single disk) - Montado en: $mount_point"
|
||
else
|
||
raid_info="BTRFS (Single disk)"
|
||
fi
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Verificar ZFS - método corregido con sed
|
||
if command -v zpool &> /dev/null; then
|
||
# Obtener lista de todos los pools
|
||
local all_pools=$(zpool list -H -o name 2>/dev/null)
|
||
|
||
for pool in $all_pools; do
|
||
if [ -n "$pool" ]; then
|
||
# Obtener dispositivos del pool usando sed (funciona mejor)
|
||
local pool_devices=$(zpool status "$pool" 2>/dev/null | sed -n '/^\s*sd[a-z]/p' | awk '{print $1}')
|
||
|
||
# Verificar si el disco está en la lista
|
||
if echo "$pool_devices" | grep -q "^${disk}$"; then
|
||
local pool_health=$(zpool list -H -o health "$pool" 2>/dev/null)
|
||
local pool_size=$(zpool list -H -o size "$pool" 2>/dev/null)
|
||
local pool_type=$(zpool status "$pool" 2>/dev/null | grep -o 'raidz[0-9]*-[0-9]*\|mirror-[0-9]*' | head -1)
|
||
|
||
# Si no hay pool_type específico, es un stripe
|
||
if [ -z "$pool_type" ]; then
|
||
pool_type="stripe"
|
||
fi
|
||
|
||
raid_info="ZFS Pool: $pool ($pool_type, $pool_health, $pool_size)"
|
||
break
|
||
fi
|
||
|
||
# También verificar otros tipos de dispositivos (nvme, etc.)
|
||
if [ -z "$raid_info" ]; then
|
||
local all_devices=$(zpool status "$pool" 2>/dev/null | sed -n '/^\s*[a-z]/p' | grep -v 'raidz\|mirror\|spare\|log\|cache\|replacing' | awk '{print $1}')
|
||
if echo "$all_devices" | grep -q "^${disk}$"; then
|
||
local pool_health=$(zpool list -H -o health "$pool" 2>/dev/null)
|
||
local pool_size=$(zpool list -H -o size "$pool" 2>/dev/null)
|
||
local pool_type=$(zpool status "$pool" 2>/dev/null | grep -o 'raidz[0-9]*-[0-9]*\|mirror-[0-9]*' | head -1)
|
||
|
||
# Si no hay pool_type específico, es un stripe
|
||
if [ -z "$pool_type" ]; then
|
||
pool_type="stripe"
|
||
fi
|
||
|
||
raid_info="ZFS Pool: $pool ($pool_type, $pool_health, $pool_size)"
|
||
break
|
||
fi
|
||
fi
|
||
|
||
# También verificar particiones (sdc1, sdc9, etc.)
|
||
local disk_partitions=$(lsblk -ln -o NAME "/dev/$disk" 2>/dev/null | grep -v "^${disk##*/}$")
|
||
for partition in $disk_partitions; do
|
||
if echo "$pool_devices $all_devices" | grep -q "^${partition}$"; then
|
||
local pool_health=$(zpool list -H -o health "$pool" 2>/dev/null)
|
||
local pool_size=$(zpool list -H -o size "$pool" 2>/dev/null)
|
||
local pool_type=$(zpool status "$pool" 2>/dev/null | grep -o 'raidz[0-9]*-[0-9]*\|mirror-[0-9]*' | head -1)
|
||
|
||
# Si no hay pool_type específico, es un stripe
|
||
if [ -z "$pool_type" ]; then
|
||
pool_type="stripe"
|
||
fi
|
||
|
||
raid_info="ZFS Pool: $pool ($pool_type, $pool_health, $pool_size)"
|
||
break 2
|
||
fi
|
||
done
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# Verificar mdadm (Linux Software RAID)
|
||
if command -v mdadm &> /dev/null; then
|
||
local md_array=$(mdadm --examine "/dev/$disk" 2>/dev/null | grep "Array UUID" | awk '{print $4}')
|
||
if [ -n "$md_array" ]; then
|
||
local md_name=$(mdadm --examine "/dev/$disk" 2>/dev/null | grep "Name" | awk '{print $3}')
|
||
raid_info="mdadm RAID: $md_name (UUID: $md_array)"
|
||
fi
|
||
fi
|
||
|
||
# Verificar LVM
|
||
if command -v pvdisplay &> /dev/null; then
|
||
if pvdisplay "/dev/$disk" 2>/dev/null | grep -q "PV Name"; then
|
||
local vg_name=$(pvdisplay "/dev/$disk" 2>/dev/null | grep "VG Name" | awk '{print $3}')
|
||
raid_info="LVM Physical Volume (VG: $vg_name)"
|
||
fi
|
||
fi
|
||
|
||
# Verificar si tiene particiones montadas (que no sean ZFS)
|
||
if mount | grep -q "/dev/$disk" && [ -z "$(echo "$raid_info" | grep ZFS)" ]; then
|
||
local mount_points=$(mount | grep "/dev/$disk" | awk '{print $3}' | tr '\n' ' ')
|
||
if [ -n "$raid_info" ]; then
|
||
raid_info="$raid_info, Montado en: $mount_points"
|
||
else
|
||
raid_info="Montado en: $mount_points"
|
||
fi
|
||
fi
|
||
|
||
echo "$raid_info"
|
||
}
|
||
|
||
# Función para eliminar pools ZFS específicos de forma segura
|
||
destroy_zfs_pool_safely() {
|
||
local pool_name="$1"
|
||
local force="${2:-false}"
|
||
|
||
if [ -z "$pool_name" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "ZFS pool name not specified"
|
||
else
|
||
show_error "Nombre de pool ZFS no especificado"
|
||
fi
|
||
return 1
|
||
fi
|
||
|
||
# Verificar que el pool existe
|
||
if ! zpool list -H -o name 2>/dev/null | grep -q "^${pool_name}$"; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "ZFS pool '$pool_name' not found"
|
||
else
|
||
show_warning "Pool ZFS '$pool_name' no encontrado"
|
||
fi
|
||
return 0
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "🗑️ Preparing deletion of ZFS pool: '$pool_name'"
|
||
else
|
||
show_warning "🗑️ Preparando eliminación del pool ZFS: '$pool_name'"
|
||
fi
|
||
|
||
# Mostrar información del pool antes de eliminar
|
||
local pool_size=$(zpool list -H -o size "$pool_name" 2>/dev/null)
|
||
local pool_health=$(zpool list -H -o health "$pool_name" 2>/dev/null)
|
||
local pool_devices=$(zpool status "$pool_name" 2>/dev/null | grep -E "^\s+[a-z]" | awk '{print $1}' | grep -v "raidz\|mirror\|spare\|log\|cache\|replacing")
|
||
|
||
echo " 📊 Tamaño: $pool_size"
|
||
echo " 💚 Estado: $pool_health"
|
||
echo " 💿 Dispositivos: $(echo $pool_devices | tr '\n' ' ')"
|
||
|
||
# Mostrar datasets que se eliminarán
|
||
local datasets=$(zfs list -H -o name -r "$pool_name" 2>/dev/null)
|
||
if [ -n "$datasets" ]; then
|
||
echo " 📁 Datasets que se eliminarán:"
|
||
for dataset in $datasets; do
|
||
local used=$(zfs list -H -o used "$dataset" 2>/dev/null)
|
||
echo " • $dataset (Usado: $used)"
|
||
done
|
||
fi
|
||
|
||
# Mostrar snapshots que se eliminarán
|
||
local snapshots=$(zfs list -t snapshot -H -o name -r "$pool_name" 2>/dev/null)
|
||
if [ -n "$snapshots" ]; then
|
||
echo " 📸 Snapshots que se eliminarán:"
|
||
for snapshot in $snapshots; do
|
||
echo " • $snapshot"
|
||
done
|
||
fi
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ THIS ACTION WILL PERMANENTLY DELETE:"
|
||
show_warning " • The complete ZFS pool '$pool_name'"
|
||
show_warning " • All datasets and their data"
|
||
show_warning " • All snapshots"
|
||
show_warning " • Automatic mount configuration"
|
||
else
|
||
show_warning "⚠️ ESTA ACCIÓN ELIMINARÁ PERMANENTEMENTE:"
|
||
show_warning " • El pool ZFS '$pool_name' completo"
|
||
show_warning " • Todos los datasets y sus datos"
|
||
show_warning " • Todos los snapshots"
|
||
show_warning " • Configuración de montaje automático"
|
||
fi
|
||
echo ""
|
||
|
||
if [ "$force" != "true" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
if ! confirm "Are you COMPLETELY SURE to delete pool '$pool_name'?"; then
|
||
show_message "Deletion cancelled by user"
|
||
return 1
|
||
fi
|
||
else
|
||
if ! confirm "¿Estás COMPLETAMENTE SEGURO de eliminar el pool '$pool_name'?"; then
|
||
show_message "Eliminación cancelada por el usuario"
|
||
return 1
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Proceder con la eliminación
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "🔄 Deleting ZFS pool '$pool_name'..."
|
||
else
|
||
show_message "🔄 Eliminando pool ZFS '$pool_name'..."
|
||
fi
|
||
|
||
# 1. Desmontार todos los datasets
|
||
if [ -n "$datasets" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Unmounting datasets..."
|
||
else
|
||
show_message "Desmontando datasets..."
|
||
fi
|
||
for dataset in $datasets; do
|
||
sudo zfs unmount "$dataset" 2>/dev/null || true
|
||
done
|
||
fi
|
||
|
||
# 2. Intentar exportar el pool primero
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Exporting pool..."
|
||
else
|
||
show_message "Exportando pool..."
|
||
fi
|
||
sudo zpool export "$pool_name" 2>/dev/null || true
|
||
sleep 1
|
||
|
||
# 3. Destruir el pool
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Destroying pool..."
|
||
else
|
||
show_message "Destruyendo pool..."
|
||
fi
|
||
if sudo zpool destroy -f "$pool_name" 2>/dev/null; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ ZFS pool '$pool_name' deleted successfully"
|
||
else
|
||
show_message "✅ Pool ZFS '$pool_name' eliminado exitosamente"
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ Standard attempt failed, forcing deletion..."
|
||
else
|
||
show_warning "⚠️ Intento estándar falló, forzando eliminación..."
|
||
fi
|
||
|
||
# Intentar importar y destruir forzadamente
|
||
sudo zpool import "$pool_name" 2>/dev/null || true
|
||
sleep 1
|
||
|
||
if sudo zpool destroy -f "$pool_name" 2>/dev/null; then
|
||
show_message "✅ Pool ZFS '$pool_name' eliminado forzadamente"
|
||
else
|
||
show_error "❌ No se pudo eliminar el pool '$pool_name'"
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
# 4. Limpiar referencias en servicios de sistema
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Cleaning system configuration..."
|
||
else
|
||
show_message "Limpiando configuración del sistema..."
|
||
fi
|
||
|
||
# Limpiar cache de zpool
|
||
sudo rm -f /etc/zfs/zpool.cache 2>/dev/null || true
|
||
|
||
# Regenerar cache
|
||
sudo zpool import -a 2>/dev/null || true
|
||
|
||
return 0
|
||
}
|
||
|
||
# Función para eliminar filesystem BTRFS de forma segura
|
||
destroy_btrfs_safely() {
|
||
local disk="$1"
|
||
local force="${2:-false}"
|
||
|
||
if [ -z "$disk" ]; then
|
||
show_error "Disco no especificado para eliminación BTRFS"
|
||
return 1
|
||
fi
|
||
|
||
# Verificar que es BTRFS
|
||
if ! btrfs filesystem show "/dev/$disk" 2>/dev/null | grep -q "uuid:"; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "No BTRFS filesystem found on /dev/$disk"
|
||
else
|
||
show_warning "No se encontró filesystem BTRFS en /dev/$disk"
|
||
fi
|
||
return 0
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "🗑️ Preparing deletion of BTRFS filesystem on: /dev/$disk"
|
||
else
|
||
show_warning "🗑️ Preparando eliminación del filesystem BTRFS en: /dev/$disk"
|
||
fi
|
||
|
||
# Obtener información del filesystem
|
||
local btrfs_uuid=$(btrfs filesystem show "/dev/$disk" 2>/dev/null | grep "uuid:" | awk '{print $4}')
|
||
local btrfs_size=$(lsblk -dpno SIZE "/dev/$disk" | tr -d ' ')
|
||
local mount_point=$(mount | grep "/dev/$disk" | awk '{print $3}' | head -1)
|
||
|
||
echo " 📊 Tamaño: $btrfs_size"
|
||
echo " 🆔 UUID: $btrfs_uuid"
|
||
if [ -n "$mount_point" ]; then
|
||
echo " 📁 Montado en: $mount_point"
|
||
fi
|
||
|
||
# Mostrar subvolúmenes si existen
|
||
if [ -n "$mount_point" ]; then
|
||
local subvolumes=$(btrfs subvolume list "$mount_point" 2>/dev/null | awk '{print $9}')
|
||
if [ -n "$subvolumes" ]; then
|
||
echo " 📂 Subvolúmenes que se eliminarán:"
|
||
for subvol in $subvolumes; do
|
||
echo " • $subvol"
|
||
done
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ THIS ACTION WILL PERMANENTLY DELETE:"
|
||
show_warning " • The complete BTRFS filesystem on /dev/$disk"
|
||
show_warning " • All data and subvolumes"
|
||
show_warning " • Automatic mount entries in /etc/fstab"
|
||
else
|
||
show_warning "⚠️ ESTA ACCIÓN ELIMINARÁ PERMANENTEMENTE:"
|
||
show_warning " • El filesystem BTRFS completo en /dev/$disk"
|
||
show_warning " • Todos los datos y subvolúmenes"
|
||
show_warning " • Entradas de montaje automático en /etc/fstab"
|
||
fi
|
||
echo ""
|
||
|
||
if [ "$force" != "true" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
if ! confirm "Are you COMPLETELY SURE to delete BTRFS on /dev/$disk?"; then
|
||
show_message "Deletion cancelled by user"
|
||
return 1
|
||
fi
|
||
else
|
||
if ! confirm "¿Estás COMPLETAMENTE SEGURO de eliminar el BTRFS en /dev/$disk?"; then
|
||
show_message "Eliminación cancelada por el usuario"
|
||
return 1
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Proceder con la eliminación
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "🔄 Deleting BTRFS filesystem on /dev/$disk..."
|
||
else
|
||
show_message "🔄 Eliminando filesystem BTRFS en /dev/$disk..."
|
||
fi
|
||
|
||
# 1. Desmontar el filesystem
|
||
if [ -n "$mount_point" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Unmounting $mount_point..."
|
||
else
|
||
show_message "Desmontando $mount_point..."
|
||
fi
|
||
sudo umount "$mount_point" 2>/dev/null || sudo umount -f "$mount_point" 2>/dev/null || true
|
||
fi
|
||
|
||
# Desmontar cualquier partición del disco
|
||
sudo umount "/dev/$disk"* 2>/dev/null || true
|
||
|
||
# 2. Eliminar entradas de /etc/fstab específicas de BTRFS de forma segura
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Removing BTRFS entries from /etc/fstab..."
|
||
else
|
||
show_message "Eliminando entradas BTRFS de /etc/fstab..."
|
||
fi
|
||
if [ -n "$btrfs_uuid" ]; then
|
||
# Crear backup de fstab con timestamp
|
||
local backup_file="/etc/fstab.backup.$(date +%Y%m%d-%H%M%S)"
|
||
sudo cp /etc/fstab "$backup_file" 2>/dev/null || true
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "📋 fstab backup created: $backup_file"
|
||
else
|
||
show_message "📋 Backup de fstab creado: $backup_file"
|
||
fi
|
||
|
||
# Verificar qué entradas existen antes de eliminar
|
||
local existing_entries=$(grep -E "UUID=$btrfs_uuid" /etc/fstab 2>/dev/null | grep -i btrfs || true)
|
||
if [ -n "$existing_entries" ]; then
|
||
show_message "📝 Entradas BTRFS encontradas en /etc/fstab:"
|
||
echo "$existing_entries" | while read -r entry; do
|
||
echo " • $entry"
|
||
done
|
||
|
||
# Eliminar entradas por UUID solo si el tipo de filesystem es btrfs
|
||
# Usar patrones más específicos para mayor seguridad
|
||
sudo sed -i "/^[[:space:]]*UUID=$btrfs_uuid[[:space:]].*[[:space:]]btrfs[[:space:]]/d" /etc/fstab 2>/dev/null || true
|
||
sudo sed -i "/^[[:space:]]*UUID=$btrfs_uuid[[:space:]].*[[:space:]]btrfs$/d" /etc/fstab 2>/dev/null || true
|
||
|
||
# Verificar si las entradas fueron eliminadas
|
||
local remaining_entries=$(grep -E "UUID=$btrfs_uuid" /etc/fstab 2>/dev/null | grep -i btrfs || true)
|
||
if [ -z "$remaining_entries" ]; then
|
||
show_message "✅ Entradas BTRFS eliminadas exitosamente de /etc/fstab"
|
||
else
|
||
show_warning "⚠️ Algunas entradas BTRFS permanecen en /etc/fstab:"
|
||
echo "$remaining_entries" | while read -r entry; do
|
||
echo " • $entry"
|
||
done
|
||
fi
|
||
else
|
||
show_message "ℹ️ No se encontraron entradas BTRFS automount en /etc/fstab para UUID: $btrfs_uuid"
|
||
fi
|
||
fi
|
||
|
||
# También verificar entradas por device path (menos común pero posible)
|
||
local device_entries=$(grep -E "/dev/$disk" /etc/fstab 2>/dev/null | grep -i btrfs || true)
|
||
if [ -n "$device_entries" ]; then
|
||
show_message "📝 Entradas por device path encontradas:"
|
||
echo "$device_entries" | while read -r entry; do
|
||
echo " • $entry"
|
||
done
|
||
|
||
# Eliminar por device path pero solo líneas que contengan btrfs
|
||
sudo sed -i "\|^[[:space:]]*/dev/$disk[[:space:]].*[[:space:]]btrfs[[:space:]]|d" /etc/fstab 2>/dev/null || true
|
||
sudo sed -i "\|^[[:space:]]*/dev/$disk[0-9]*[[:space:]].*[[:space:]]btrfs[[:space:]]|d" /etc/fstab 2>/dev/null || true
|
||
|
||
# Verificar si fueron eliminadas
|
||
local remaining_device_entries=$(grep -E "/dev/$disk" /etc/fstab 2>/dev/null | grep -i btrfs || true)
|
||
if [ -z "$remaining_device_entries" ]; then
|
||
show_message "✅ Entradas por device path eliminadas exitosamente"
|
||
fi
|
||
fi
|
||
|
||
# 3. Limpiar metadatos BTRFS
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Cleaning BTRFS metadata..."
|
||
else
|
||
show_message "Limpiando metadatos BTRFS..."
|
||
fi
|
||
sudo wipefs -af "/dev/$disk" 2>/dev/null || true
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ BTRFS filesystem on /dev/$disk deleted successfully"
|
||
else
|
||
show_message "✅ Filesystem BTRFS en /dev/$disk eliminado exitosamente"
|
||
fi
|
||
return 0
|
||
}
|
||
|
||
# Función para eliminar array BTRFS completo de forma segura
|
||
destroy_btrfs_array_safely() {
|
||
local primary_disk="$1"
|
||
local array_uuid="$2"
|
||
|
||
if [ -z "$primary_disk" ] || [ -z "$array_uuid" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "Incorrect parameters for BTRFS array deletion"
|
||
else
|
||
show_error "Parámetros incorrectos para eliminación de array BTRFS"
|
||
fi
|
||
return 1
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "🗑️ Deleting complete BTRFS array (UUID: $array_uuid)"
|
||
else
|
||
show_warning "🗑️ Eliminando array BTRFS completo (UUID: $array_uuid)"
|
||
fi
|
||
|
||
# Obtener información completa del array
|
||
local btrfs_info=$(sudo btrfs filesystem show "/dev/$primary_disk" 2>/dev/null)
|
||
local total_devices=$(echo "$btrfs_info" | grep "Total devices" | awk '{print $3}')
|
||
local all_devices=$(echo "$btrfs_info" | grep "devid" | awk '{print $NF}' | sed 's|/dev/||')
|
||
local mount_point=$(mount | grep "UUID=$array_uuid" | awk '{print $3}' | head -1)
|
||
|
||
echo " 📊 Total de dispositivos: $total_devices"
|
||
echo " 📀 Dispositivos: $all_devices"
|
||
if [ -n "$mount_point" ]; then
|
||
echo " 📁 Montado en: $mount_point"
|
||
fi
|
||
|
||
# Obtener tipo de RAID si está montado
|
||
local raid_profile=""
|
||
if [ -n "$mount_point" ]; then
|
||
raid_profile=$(sudo btrfs filesystem usage "$mount_point" 2>/dev/null | grep "Data," | head -1 | awk '{print $1}' | cut -d',' -f2 | cut -d':' -f1)
|
||
if [ -n "$raid_profile" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 🔧 RAID Configuration: $raid_profile"
|
||
else
|
||
echo " 🔧 Configuración RAID: $raid_profile"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ THIS ACTION WILL PERMANENTLY DELETE:"
|
||
show_warning " • The entire BTRFS array ($total_devices devices)"
|
||
show_warning " • All data and subvolumes"
|
||
show_warning " • Automatic mount entries in /etc/fstab"
|
||
else
|
||
show_warning "⚠️ ESTA ACCIÓN ELIMINARÁ PERMANENTEMENTE:"
|
||
show_warning " • Todo el array BTRFS ($total_devices dispositivos)"
|
||
show_warning " • Todos los datos y subvolúmenes"
|
||
show_warning " • Entradas de montaje automático en /etc/fstab"
|
||
fi
|
||
echo ""
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
if ! confirm "Are you COMPLETELY SURE to delete this complete BTRFS array?"; then
|
||
show_message "Deletion cancelled by user"
|
||
return 1
|
||
fi
|
||
else
|
||
if ! confirm "¿Estás COMPLETAMENTE SEGURO de eliminar este array BTRFS completo?"; then
|
||
show_message "Eliminación cancelada por el usuario"
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
# Proceder con la eliminación del array completo
|
||
show_message "🔄 Eliminando array BTRFS..."
|
||
|
||
# 1. Desmontar el filesystem
|
||
if [ -n "$mount_point" ]; then
|
||
show_message "Desmontando $mount_point..."
|
||
sudo umount "$mount_point" 2>/dev/null || sudo umount -f "$mount_point" 2>/dev/null || true
|
||
fi
|
||
|
||
# Desmontar todos los dispositivos del array
|
||
for device in $all_devices; do
|
||
sudo umount "/dev/$device"* 2>/dev/null || true
|
||
done
|
||
|
||
# 2. Eliminar entradas de /etc/fstab para el array completo
|
||
show_message "Eliminando entradas del array BTRFS de /etc/fstab..."
|
||
local backup_file="/etc/fstab.backup.$(date +%Y%m%d-%H%M%S)"
|
||
sudo cp /etc/fstab "$backup_file" 2>/dev/null || true
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "📋 fstab backup created: $backup_file"
|
||
else
|
||
show_message "📋 Backup de fstab creado: $backup_file"
|
||
fi
|
||
|
||
# Verificar entradas existentes
|
||
local existing_entries=$(grep -E "UUID=$array_uuid" /etc/fstab 2>/dev/null | grep -i btrfs || true)
|
||
if [ -n "$existing_entries" ]; then
|
||
show_message "📝 Eliminando entradas del array BTRFS:"
|
||
echo "$existing_entries" | while read -r entry; do
|
||
echo " • $entry"
|
||
done
|
||
|
||
# Eliminar entradas por UUID del array
|
||
sudo sed -i "/^[[:space:]]*UUID=$array_uuid[[:space:]].*[[:space:]]btrfs[[:space:]]/d" /etc/fstab 2>/dev/null || true
|
||
sudo sed -i "/^[[:space:]]*UUID=$array_uuid[[:space:]].*[[:space:]]btrfs$/d" /etc/fstab 2>/dev/null || true
|
||
|
||
# Verificar eliminación
|
||
local remaining_entries=$(grep -E "UUID=$array_uuid" /etc/fstab 2>/dev/null | grep -i btrfs || true)
|
||
if [ -z "$remaining_entries" ]; then
|
||
show_message "✅ Entradas del array eliminadas exitosamente de /etc/fstab"
|
||
else
|
||
show_warning "⚠️ Algunas entradas del array permanecen en /etc/fstab"
|
||
fi
|
||
else
|
||
show_message "ℹ️ No se encontraron entradas automount para este array"
|
||
fi
|
||
|
||
# 3. Limpiar metadatos BTRFS de todos los dispositivos
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Cleaning BTRFS metadata from all devices..."
|
||
else
|
||
show_message "Limpiando metadatos BTRFS de todos los dispositivos..."
|
||
fi
|
||
for device in $all_devices; do
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message " Cleaning /dev/$device..."
|
||
else
|
||
show_message " Limpiando /dev/$device..."
|
||
fi
|
||
sudo wipefs -af "/dev/$device" 2>/dev/null || true
|
||
done
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ Complete BTRFS array deleted successfully"
|
||
show_message " 📀 Devices cleaned: $all_devices"
|
||
else
|
||
show_message "✅ Array BTRFS completo eliminado exitosamente"
|
||
show_message " 📀 Dispositivos limpiados: $all_devices"
|
||
fi
|
||
return 0
|
||
}
|
||
|
||
# Función para limpiar disco de configuraciones RAID anteriores
|
||
clean_disk() {
|
||
local disk="$1"
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Cleaning disk /dev/$disk..."
|
||
else
|
||
show_message "Limpiando disco /dev/$disk..."
|
||
fi
|
||
|
||
# Desmontar si está montado
|
||
if mount | grep -q "/dev/$disk"; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Unmounting /dev/$disk..."
|
||
else
|
||
show_message "Desmontando /dev/$disk..."
|
||
fi
|
||
sudo umount "/dev/$disk"* 2>/dev/null || true
|
||
fi
|
||
|
||
# Verificar y destruir pools ZFS que usen este disco
|
||
if command -v zpool &> /dev/null; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Checking ZFS pools using /dev/$disk..."
|
||
else
|
||
show_message "Verificando pools ZFS que usan /dev/$disk..."
|
||
fi
|
||
|
||
# Obtener lista de todos los pools
|
||
local all_pools=$(zpool list -H -o name 2>/dev/null)
|
||
local pools_to_destroy=()
|
||
|
||
for pool in $all_pools; do
|
||
if [ -n "$pool" ]; then
|
||
# Verificar si este disco está en el pool
|
||
if zpool status "$pool" 2>/dev/null | sed -n '/^\s*sd[a-z]/p' | awk '{print $1}' | grep -q "^${disk}$"; then
|
||
pools_to_destroy+=("$pool")
|
||
elif zpool status "$pool" 2>/dev/null | sed -n '/^\s*[a-z]/p' | grep -v 'raidz\|mirror\|spare\|log\|cache\|replacing' | awk '{print $1}' | grep -q "^${disk}$"; then
|
||
pools_to_destroy+=("$pool")
|
||
fi
|
||
|
||
# También verificar particiones
|
||
local disk_partitions=$(lsblk -ln -o NAME "/dev/$disk" 2>/dev/null | grep -v "^${disk##*/}$")
|
||
for partition in $disk_partitions; do
|
||
if zpool status "$pool" 2>/dev/null | grep -q "$partition"; then
|
||
pools_to_destroy+=("$pool")
|
||
break
|
||
fi
|
||
done
|
||
fi
|
||
done
|
||
|
||
# Eliminar duplicados de pools
|
||
local unique_pools=($(printf "%s\n" "${pools_to_destroy[@]}" | sort -u))
|
||
|
||
# Destruir pools encontrados usando la función segura
|
||
for pool in "${unique_pools[@]}"; do
|
||
if [ -n "$pool" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "🗑️ Detected ZFS pool '$pool' using disk /dev/$disk"
|
||
else
|
||
show_warning "🗑️ Detectado pool ZFS '$pool' usando el disco /dev/$disk"
|
||
fi
|
||
|
||
# Usar la función de eliminación segura
|
||
if ! destroy_zfs_pool_safely "$pool" "true"; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "❌ Error deleting pool '$pool'"
|
||
show_message "Continuing with manual cleanup..."
|
||
show_warning "⚠️ Trying emergency method..."
|
||
else
|
||
show_error "❌ Error eliminando el pool '$pool'"
|
||
show_message "Continuando con limpieza manual..."
|
||
show_warning "⚠️ Intentando método de emergencia..."
|
||
fi
|
||
|
||
# Fallback a método anterior si la función segura falla
|
||
sudo zpool export "$pool" 2>/dev/null || true
|
||
sleep 1
|
||
sudo zpool destroy -f "$pool" 2>/dev/null || true
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Limpiar etiquetas ZFS residuales en el disco y particiones
|
||
sudo zpool labelclear -f "/dev/$disk" 2>/dev/null || true
|
||
|
||
# Limpiar particiones ZFS si existen
|
||
local disk_partitions=$(lsblk -ln -o NAME "/dev/$disk" 2>/dev/null | grep -v "^${disk##*/}$")
|
||
for partition in $disk_partitions; do
|
||
local full_partition="/dev/${partition}"
|
||
sudo zpool labelclear -f "$full_partition" 2>/dev/null || true
|
||
done
|
||
fi
|
||
|
||
# Verificar y limpiar BTRFS usando la función segura
|
||
if command -v btrfs &> /dev/null; then
|
||
if btrfs filesystem show "/dev/$disk" 2>/dev/null | grep -q "uuid:"; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "🗑️ Detected BTRFS filesystem on /dev/$disk"
|
||
else
|
||
show_warning "🗑️ Detectado filesystem BTRFS en /dev/$disk"
|
||
fi
|
||
|
||
# Usar la función de eliminación segura para BTRFS
|
||
if ! destroy_btrfs_safely "$disk" "true"; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "❌ Error deleting BTRFS filesystem"
|
||
show_message "Continuing with manual cleanup..."
|
||
else
|
||
show_error "❌ Error eliminando filesystem BTRFS"
|
||
show_message "Continuando con limpieza manual..."
|
||
fi
|
||
|
||
# Fallback a limpieza básica
|
||
sudo wipefs -a "/dev/$disk" 2>/dev/null || true
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Limpiar metadatos mdadm
|
||
if command -v mdadm &> /dev/null; then
|
||
sudo mdadm --zero-superblock "/dev/$disk" 2>/dev/null || true
|
||
fi
|
||
|
||
# Limpiar metadatos LVM
|
||
if command -v pvremove &> /dev/null; then
|
||
sudo pvremove -ff "/dev/$disk" 2>/dev/null || true
|
||
fi
|
||
|
||
# Limpiar tabla de particiones y metadatos completamente
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "🧹 Cleaning partition table and metadata from /dev/$disk..."
|
||
else
|
||
show_message "🧹 Limpiando tabla de particiones y metadatos de /dev/$disk..."
|
||
fi
|
||
|
||
# Limpiar los primeros 100MB y los últimos 100MB del disco
|
||
sudo dd if=/dev/zero of="/dev/$disk" bs=1M count=100 2>/dev/null || true
|
||
|
||
# Obtener el tamaño del disco y limpiar el final también
|
||
local disk_size=$(lsblk -dpno SIZE "/dev/$disk" --bytes 2>/dev/null || echo "0")
|
||
if [ "$disk_size" -gt 104857600 ]; then # Si es mayor a 100MB
|
||
local seek_pos=$(( (disk_size / 1048576) - 100 )) # 100MB antes del final
|
||
sudo dd if=/dev/zero of="/dev/$disk" bs=1M seek="$seek_pos" count=100 2>/dev/null || true
|
||
fi
|
||
|
||
# Limpiar con wipefs para asegurar que no queden metadatos
|
||
sudo wipefs -af "/dev/$disk" 2>/dev/null || true
|
||
|
||
# Forzar actualización de la tabla de particiones
|
||
sudo partprobe "/dev/$disk" 2>/dev/null || true
|
||
sudo udevadm settle 2>/dev/null || true
|
||
|
||
# Esperar un poco más para que el sistema reconozca los cambios
|
||
sleep 3
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ Disk /dev/$disk completely cleaned"
|
||
else
|
||
show_message "✅ Disco /dev/$disk limpiado completamente"
|
||
fi
|
||
}
|
||
|
||
# Función para detectar discos disponibles
|
||
detect_disks() {
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Detecting available disks"
|
||
else
|
||
show_title "Detectando discos disponibles"
|
||
fi
|
||
|
||
# Obtener lista de discos, excluyendo dispositivos del sistema
|
||
AVAILABLE_DISKS=()
|
||
DISK_RAID_STATUS=()
|
||
|
||
# Obtener disco raíz
|
||
ROOT_DISK=$(lsblk -no PKNAME $(findmnt -n -o SOURCE /))
|
||
|
||
# Obtener discos con particiones montadas en puntos críticos del sistema
|
||
SYSTEM_DISKS=()
|
||
SYSTEM_DISKS+=("$ROOT_DISK")
|
||
|
||
# Detectar discos que contienen particiones del sistema
|
||
while IFS= read -r device mount_point; do
|
||
# Excluir puntos de montaje críticos del sistema
|
||
if [[ "$mount_point" == "/" ]] || [[ "$mount_point" == "/boot"* ]] || \
|
||
[[ "$mount_point" == "/usr"* ]] || [[ "$mount_point" == "/var"* ]] || \
|
||
[[ "$mount_point" == "/etc"* ]] || [[ "$mount_point" == "/lib"* ]] || \
|
||
[[ "$mount_point" == "/bin"* ]] || [[ "$mount_point" == "/sbin"* ]]; then
|
||
|
||
# Extraer el disco base del device
|
||
local base_disk=$(lsblk -no PKNAME "$device" 2>/dev/null || echo "$device" | sed 's|/dev/||' | sed 's/[0-9]*$//')
|
||
if [ -n "$base_disk" ] && [[ ! " ${SYSTEM_DISKS[*]} " =~ " ${base_disk} " ]]; then
|
||
SYSTEM_DISKS+=("$base_disk")
|
||
fi
|
||
fi
|
||
done < <(findmnt -rn -o SOURCE,TARGET | grep -E "^/dev/")
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "📋 System disks excluded: ${SYSTEM_DISKS[*]}"
|
||
else
|
||
show_message "📋 Discos del sistema excluidos: ${SYSTEM_DISKS[*]}"
|
||
fi
|
||
|
||
while IFS= read -r disk; do
|
||
# Excluir discos del sistema, dispositivos loop, y particiones
|
||
if [[ ! " ${SYSTEM_DISKS[*]} " =~ " ${disk} " ]] && \
|
||
[[ "$disk" != loop* ]] && [[ "$disk" != ram* ]] && \
|
||
[[ "$disk" != *boot* ]] && [[ ! "$disk" =~ [0-9]$ ]]; then
|
||
|
||
# Verificar que sea un disco completo, no una partición
|
||
if lsblk -dpno TYPE "/dev/$disk" 2>/dev/null | grep -q "disk"; then
|
||
AVAILABLE_DISKS+=("$disk")
|
||
# Verificar estado RAID del disco
|
||
raid_status=$(check_disk_raid_status "$disk")
|
||
DISK_RAID_STATUS+=("$raid_status")
|
||
fi
|
||
fi
|
||
done < <(lsblk -dpno NAME | sed 's|/dev/||' | grep -v '^$')
|
||
|
||
if [ ${#AVAILABLE_DISKS[@]} -eq 0 ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "No available disks found for RAID"
|
||
else
|
||
show_error "No se encontraron discos disponibles para RAID"
|
||
fi
|
||
exit 1
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Found disks:"
|
||
else
|
||
show_message "Discos encontrados:"
|
||
fi
|
||
local disks_with_raid=false
|
||
|
||
for i in "${!AVAILABLE_DISKS[@]}"; do
|
||
disk="/dev/${AVAILABLE_DISKS[$i]}"
|
||
size=$(lsblk -dpno SIZE "$disk" | tr -d ' ')
|
||
model=$(lsblk -dpno MODEL "$disk" | tr -d ' ')
|
||
status="${DISK_RAID_STATUS[$i]}"
|
||
|
||
if [ -n "$status" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo -e " $((i+1)). ${AVAILABLE_DISKS[$i]} - $size - $model ${RED}[IN USE: $status]${NC}"
|
||
else
|
||
echo -e " $((i+1)). ${AVAILABLE_DISKS[$i]} - $size - $model ${RED}[EN USO: $status]${NC}"
|
||
fi
|
||
disks_with_raid=true
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " $((i+1)). ${AVAILABLE_DISKS[$i]} - $size - $model [FREE]"
|
||
else
|
||
echo " $((i+1)). ${AVAILABLE_DISKS[$i]} - $size - $model [LIBRE]"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Si hay discos en RAID existentes, preguntar al usuario
|
||
if [ "$disks_with_raid" = true ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "ATTENTION! Some disks are being used in existing RAID configurations."
|
||
show_warning "If you continue, you will have the option to clean these disks before creating the new RAID."
|
||
show_warning "This will DESTROY all data on those disks."
|
||
|
||
if ! confirm "Do you want to continue with the configuration?"; then
|
||
show_message "Configuration cancelled by user"
|
||
exit 0
|
||
fi
|
||
else
|
||
show_warning "¡ATENCIÓN! Algunos discos están siendo utilizados en configuraciones RAID existentes."
|
||
show_warning "Si continúas, tendrás la opción de limpiar estos discos antes de crear el nuevo RAID."
|
||
show_warning "Esto DESTRUIRÁ todos los datos en esos discos."
|
||
|
||
if ! confirm "¿Deseas continuar con la configuración?"; then
|
||
show_message "Configuración cancelada por el usuario"
|
||
exit 0
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Detectar NVME
|
||
NVME_DISK=""
|
||
for disk in "${AVAILABLE_DISKS[@]}"; do
|
||
if [[ "$disk" == nvme* ]]; then
|
||
NVME_DISK="$disk"
|
||
show_message "Detectado disco NVME: $NVME_DISK"
|
||
break
|
||
fi
|
||
done
|
||
}
|
||
|
||
# Función para seleccionar tipo de filesystem
|
||
select_filesystem() {
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Filesystem Selection"
|
||
echo "Select the type of RAID filesystem:"
|
||
else
|
||
show_title "Selección de Sistema de Archivos"
|
||
echo "Selecciona el tipo de sistema de archivos RAID:"
|
||
fi
|
||
echo "1. BTRFS"
|
||
echo "2. ZFS"
|
||
|
||
while true; do
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
read -p "Select an option (1-2): " choice
|
||
else
|
||
read -p "Selecciona una opción (1-2): " choice
|
||
fi
|
||
case $choice in
|
||
1)
|
||
FILESYSTEM_TYPE="btrfs"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "NOTE: In BTRFS, RAID 5/6 is still experimental"
|
||
else
|
||
show_warning "NOTA: En BTRFS, RAID 5/6 aún es experimental"
|
||
fi
|
||
break
|
||
;;
|
||
2)
|
||
FILESYSTEM_TYPE="zfs"
|
||
break
|
||
;;
|
||
*)
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Invalid option. Please select 1 or 2."
|
||
else
|
||
echo "Opción inválida. Por favor selecciona 1 o 2."
|
||
fi
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
# Función para mostrar tipos de RAID
|
||
show_raid_types() {
|
||
if [ "$FILESYSTEM_TYPE" = "btrfs" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Available BTRFS RAID types:"
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Available RAID types in BTRFS:"
|
||
else
|
||
echo "Tipos de RAID disponibles en BTRFS:"
|
||
fi
|
||
fi
|
||
echo "1. RAID 0 (stripe) - No redundancy, maximum performance and capacity"
|
||
echo "2. RAID 1 (mirror) - Data mirrored across drives, 50% capacity"
|
||
echo "3. RAID 5 - Single drive fault tolerance with parity (EXPERIMENTAL)"
|
||
echo "4. RAID 6 - Dual drive fault tolerance with parity (EXPERIMENTAL)"
|
||
echo "5. RAID 10 - Combination of RAID 0 and 1, requires 4+ drives"
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Available ZFS RAID types:"
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Available RAID types in ZFS:"
|
||
else
|
||
echo "Tipos de RAID disponibles en ZFS:"
|
||
fi
|
||
fi
|
||
echo "1. Stripe - No redundancy, maximum performance"
|
||
echo "2. Mirror - Data mirrored across drives"
|
||
echo "3. RAIDZ1 - Single parity, equivalent to RAID 5"
|
||
echo "4. RAIDZ2 - Double parity, equivalent to RAID 6"
|
||
echo "5. RAIDZ3 - Triple parity, requires 4+ drives"
|
||
fi
|
||
}
|
||
|
||
# Función para calcular capacidad del RAID
|
||
calculate_raid_capacity() {
|
||
local raid_type="$1"
|
||
local disk_sizes=("${@:2}")
|
||
local total_capacity=0
|
||
local min_size=${disk_sizes[0]}
|
||
local num_disks=${#disk_sizes[@]}
|
||
|
||
# Encontrar el disco más pequeño
|
||
for size in "${disk_sizes[@]}"; do
|
||
if [ "$size" -lt "$min_size" ]; then
|
||
min_size=$size
|
||
fi
|
||
total_capacity=$((total_capacity + size))
|
||
done
|
||
|
||
# Calcular capacidad según tipo de RAID
|
||
case $raid_type in
|
||
"raid0"|"stripe")
|
||
RAID_CAPACITY=$total_capacity
|
||
;;
|
||
"raid1"|"mirror")
|
||
RAID_CAPACITY=$min_size
|
||
;;
|
||
"raid5"|"raidz1")
|
||
RAID_CAPACITY=$(( min_size * (num_disks - 1) ))
|
||
;;
|
||
"raid6"|"raidz2")
|
||
RAID_CAPACITY=$(( min_size * (num_disks - 2) ))
|
||
;;
|
||
"raid10")
|
||
RAID_CAPACITY=$(( min_size * (num_disks / 2) ))
|
||
;;
|
||
"raidz3")
|
||
RAID_CAPACITY=$(( min_size * (num_disks - 3) ))
|
||
;;
|
||
esac
|
||
|
||
# Mostrar información si hay discos de diferente tamaño
|
||
local sizes_differ=false
|
||
for size in "${disk_sizes[@]}"; do
|
||
if [ "$size" -ne "${disk_sizes[0]}" ]; then
|
||
sizes_differ=true
|
||
break
|
||
fi
|
||
done
|
||
|
||
if [ "$sizes_differ" = true ]; then
|
||
show_warning "¡ATENCIÓN! Los discos tienen diferentes tamaños:"
|
||
for i in "${!SELECTED_DISKS[@]}"; do
|
||
local disk_gb=$(( ${disk_sizes[$i]} / 1024 / 1024 / 1024 ))
|
||
local disk_formatted=$(format_capacity "$disk_gb")
|
||
echo " ${SELECTED_DISKS[$i]}: ${disk_formatted}"
|
||
done
|
||
local raid_capacity_gb=$(( RAID_CAPACITY / 1024 / 1024 / 1024 ))
|
||
local raid_capacity_formatted=$(format_capacity "$raid_capacity_gb")
|
||
echo "Capacidad del RAID resultante: ${raid_capacity_formatted}"
|
||
echo "Se utilizará el tamaño del disco más pequeño como referencia."
|
||
|
||
if ! confirm "¿Deseas continuar con esta configuración?"; then
|
||
show_message "Configuración cancelada por el usuario"
|
||
exit 0
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# Función para formatear capacidad en la unidad más apropiada
|
||
format_capacity() {
|
||
local size_gb="$1"
|
||
|
||
if [ "$size_gb" -ge 1024 ]; then
|
||
local size_tb=$((size_gb / 1024))
|
||
local remainder=$((size_gb % 1024))
|
||
|
||
if [ "$remainder" -eq 0 ]; then
|
||
echo "${size_tb}TB"
|
||
else
|
||
# Calcular decimales para mostrar X.X TB
|
||
local decimal=$((remainder * 10 / 1024))
|
||
echo "${size_tb}.${decimal}TB"
|
||
fi
|
||
else
|
||
echo "${size_gb}GB"
|
||
fi
|
||
}
|
||
|
||
# Función para mostrar vista previa de la configuración RAID
|
||
show_raid_preview() {
|
||
local raid_type="$1"
|
||
local selected_disks=("${@:2}")
|
||
local num_disks=${#selected_disks[@]}
|
||
|
||
if [ $num_disks -eq 0 ]; then
|
||
return 0
|
||
fi
|
||
|
||
# Calcular tamaños
|
||
local disk_sizes=()
|
||
local total_raw_gb=0
|
||
local min_size_bytes=""
|
||
|
||
for disk in "${selected_disks[@]}"; do
|
||
local size_bytes=$(lsblk -dpno SIZE "/dev/$disk" --bytes)
|
||
disk_sizes+=("$size_bytes")
|
||
|
||
if [ -z "$min_size_bytes" ] || [ "$size_bytes" -lt "$min_size_bytes" ]; then
|
||
min_size_bytes="$size_bytes"
|
||
fi
|
||
|
||
local size_gb=$((size_bytes / 1024 / 1024 / 1024))
|
||
total_raw_gb=$((total_raw_gb + size_gb))
|
||
done
|
||
|
||
local min_size_gb=$((min_size_bytes / 1024 / 1024 / 1024))
|
||
local usable_gb=0
|
||
local redundancy_level=""
|
||
local failure_tolerance=""
|
||
local performance_note=""
|
||
|
||
# Calcular capacidad y características según tipo de RAID
|
||
case "$raid_type" in
|
||
"raid0"|"stripe")
|
||
usable_gb=$total_raw_gb
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
redundancy_level="❌ NO REDUNDANCY"
|
||
failure_tolerance="⚠️ 1 disk failure = TOTAL LOSS"
|
||
performance_note="🚀 Maximum performance (read and write)"
|
||
else
|
||
redundancy_level="❌ SIN REDUNDANCIA"
|
||
failure_tolerance="⚠️ Fallo de 1 disco = PÉRDIDA TOTAL"
|
||
performance_note="🚀 Máximo rendimiento (lectura y escritura)"
|
||
fi
|
||
;;
|
||
"raid1"|"mirror")
|
||
usable_gb=$min_size_gb
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
redundancy_level="✅ FULL MIRROR"
|
||
failure_tolerance="✅ Tolerates failure of up to $((num_disks-1)) disk(s)"
|
||
performance_note="⚡ Good read performance, normal write"
|
||
else
|
||
redundancy_level="✅ ESPEJO COMPLETO"
|
||
failure_tolerance="✅ Tolera fallo de hasta $((num_disks-1)) disco(s)"
|
||
performance_note="⚡ Buen rendimiento de lectura, escritura normal"
|
||
fi
|
||
;;
|
||
"raid5"|"raidz1")
|
||
usable_gb=$((min_size_gb * (num_disks - 1)))
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
redundancy_level="✅ SINGLE PARITY"
|
||
failure_tolerance="✅ Tolerates 1 disk failure"
|
||
performance_note="⚡ Good balanced performance"
|
||
else
|
||
redundancy_level="✅ PARIDAD SIMPLE"
|
||
failure_tolerance="✅ Tolera fallo de 1 disco"
|
||
performance_note="⚡ Buen rendimiento balanceado"
|
||
fi
|
||
;;
|
||
"raid6"|"raidz2")
|
||
usable_gb=$((min_size_gb * (num_disks - 2)))
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
redundancy_level="✅ DOUBLE PARITY"
|
||
failure_tolerance="✅ Tolerates up to 2 disk failures"
|
||
performance_note="⚡ Moderate performance"
|
||
else
|
||
redundancy_level="✅ PARIDAD DOBLE"
|
||
failure_tolerance="✅ Tolera fallo de hasta 2 discos"
|
||
performance_note="⚡ Rendimiento moderado"
|
||
fi
|
||
;;
|
||
"raid10")
|
||
usable_gb=$((min_size_gb * (num_disks / 2)))
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
redundancy_level="✅ MIRROR + STRIPING"
|
||
failure_tolerance="✅ Tolerates 1 disk failure per mirror"
|
||
performance_note="🚀 High performance (read and write)"
|
||
else
|
||
redundancy_level="✅ ESPEJO + STRIPING"
|
||
failure_tolerance="✅ Tolera fallo de 1 disco por espejo"
|
||
performance_note="🚀 Alto rendimiento (lectura y escritura)"
|
||
fi
|
||
;;
|
||
"raidz3")
|
||
usable_gb=$((min_size_gb * (num_disks - 3)))
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
redundancy_level="✅ TRIPLE PARITY"
|
||
failure_tolerance="✅ Tolerates up to 3 disk failures"
|
||
performance_note="⚡ Conservative performance"
|
||
else
|
||
redundancy_level="✅ PARIDAD TRIPLE"
|
||
failure_tolerance="✅ Tolera fallo de hasta 3 discos"
|
||
performance_note="⚡ Rendimiento conservador"
|
||
fi
|
||
;;
|
||
esac
|
||
|
||
local efficiency=$((usable_gb * 100 / total_raw_gb))
|
||
|
||
# Formatear capacidades
|
||
local min_size_formatted=$(format_capacity "$min_size_gb")
|
||
local total_raw_formatted=$(format_capacity "$total_raw_gb")
|
||
local usable_formatted=$(format_capacity "$usable_gb")
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "🎯 RESULTING RAID CONFIGURATION:"
|
||
echo "════════════════════════════════════════════════════════════════"
|
||
echo "📦 CAPACITY:"
|
||
echo " Disks: $num_disks x ${min_size_formatted}"
|
||
echo " Total raw capacity: ${total_raw_formatted}"
|
||
echo " Usable capacity: ${usable_formatted}"
|
||
echo " Storage efficiency: ${efficiency}%"
|
||
echo ""
|
||
echo "🔒 DATA PROTECTION:"
|
||
echo " $redundancy_level"
|
||
echo " $failure_tolerance"
|
||
echo ""
|
||
echo "⚡ PERFORMANCE:"
|
||
echo " $performance_note"
|
||
else
|
||
echo "🎯 CONFIGURACIÓN RAID RESULTANTE:"
|
||
echo "════════════════════════════════════════════════════════════════"
|
||
echo "📦 CAPACIDAD:"
|
||
echo " Discos: $num_disks x ${min_size_formatted}"
|
||
echo " Capacidad bruta total: ${total_raw_formatted}"
|
||
echo " Capacidad utilizable: ${usable_formatted}"
|
||
echo " Eficiencia de almacenamiento: ${efficiency}%"
|
||
echo ""
|
||
echo "🔒 PROTECCIÓN DE DATOS:"
|
||
echo " $redundancy_level"
|
||
echo " $failure_tolerance"
|
||
echo ""
|
||
echo "⚡ RENDIMIENTO:"
|
||
echo " $performance_note"
|
||
fi
|
||
|
||
# Verificar si hay diferencias de tamaño significativas
|
||
local max_size_bytes=$(printf '%s\n' "${disk_sizes[@]}" | sort -nr | head -1)
|
||
local size_diff=$((max_size_bytes - min_size_bytes))
|
||
local size_variance=$((size_diff * 100 / max_size_bytes))
|
||
|
||
if [ $size_variance -gt 10 ]; then
|
||
local max_size_gb=$((max_size_bytes / 1024 / 1024 / 1024))
|
||
local wasted_gb=$(((max_size_gb - min_size_gb) * num_disks))
|
||
|
||
local min_size_formatted=$(format_capacity "$min_size_gb")
|
||
local max_size_formatted=$(format_capacity "$max_size_gb")
|
||
local wasted_formatted=$(format_capacity "$wasted_gb")
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "⚠️ WARNING - SIZE DIFFERENCE:"
|
||
echo " Smallest disk: ${min_size_formatted}"
|
||
echo " Largest disk: ${max_size_formatted}"
|
||
echo " Wasted space: ~${wasted_formatted}"
|
||
echo " 💡 It's recommended to use similarly sized disks"
|
||
else
|
||
echo "⚠️ ADVERTENCIA - DIFERENCIA DE TAMAÑOS:"
|
||
echo " Disco más pequeño: ${min_size_formatted}"
|
||
echo " Disco más grande: ${max_size_formatted}"
|
||
echo " Espacio desperdiciado: ~${wasted_formatted}"
|
||
echo " 💡 Se recomienda usar discos de tamaño similar"
|
||
fi
|
||
fi
|
||
|
||
# Advertencias específicas
|
||
if [[ "$raid_type" == "raid5" || "$raid_type" == "raid6" ]] && [ "$FILESYSTEM_TYPE" = "btrfs" ]; then
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "⚠️ BTRFS WARNING:"
|
||
echo " RAID 5/6 in BTRFS is EXPERIMENTAL and may cause corruption"
|
||
else
|
||
echo "⚠️ ADVERTENCIA BTRFS:"
|
||
echo " RAID 5/6 en BTRFS es EXPERIMENTAL y puede causar corrupción"
|
||
fi
|
||
echo " 💡 Considera usar ZFS para RAID 5/6, o RAID 1/10 en BTRFS"
|
||
fi
|
||
|
||
echo "════════════════════════════════════════════════════════════════"
|
||
}
|
||
|
||
# Función para seleccionar discos
|
||
select_disks() {
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Disk Selection"
|
||
else
|
||
show_title "Selección de Discos"
|
||
fi
|
||
|
||
local min_disks=2
|
||
case $RAID_TYPE in
|
||
"raid5"|"raidz1") min_disks=3;;
|
||
"raid6"|"raidz2") min_disks=4;;
|
||
"raid10") min_disks=4;;
|
||
"raidz3") min_disks=4;;
|
||
esac
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Select disks for RAID (minimum $min_disks disks):"
|
||
echo ""
|
||
echo "📖 SELECTION INSTRUCTIONS:"
|
||
echo " Individual selection: Write disk number (ex: 3)"
|
||
echo " Multiple selection: Write numbers separated by spaces (ex: 3 4 5 6)"
|
||
echo " Range selection: Write range with dash (ex: 3-6)"
|
||
echo " Toggle selection: Write disk number again to add/remove"
|
||
echo ""
|
||
echo "🎯 SPECIAL COMMANDS:"
|
||
echo " 'clear' - Clear all selection"
|
||
echo " 'done' - Finish selection and continue"
|
||
echo ""
|
||
echo "💡 TIP: You can modify your selection at any time by entering more disk numbers"
|
||
else
|
||
show_message "Selecciona los discos para el RAID (mínimo $min_disks discos):"
|
||
echo ""
|
||
echo "📖 INSTRUCCIONES DE SELECCIÓN:"
|
||
echo " Selección individual: Escribe el número del disco (ej: 3)"
|
||
echo " Selección múltiple: Escribe números separados por espacios (ej: 3 4 5 6)"
|
||
echo " Selección por rango: Escribe rango con guión (ej: 3-6)"
|
||
echo " Alternar selección: Vuelve a escribir el número del disco para agregar/quitar"
|
||
echo ""
|
||
echo "🎯 COMANDOS ESPECIALES:"
|
||
echo " 'clear' - Limpiar toda la selección"
|
||
echo " 'done' - Finalizar selección y continuar"
|
||
echo ""
|
||
echo "💡 CONSEJO: Puedes modificar tu selección en cualquier momento ingresando más números de disco"
|
||
fi
|
||
echo ""
|
||
|
||
SELECTED_DISKS=()
|
||
SELECTED_DISK_SIZES=()
|
||
DISKS_TO_CLEAN=()
|
||
|
||
while true; do
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Available disks:"
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Available disks:"
|
||
else
|
||
echo "Discos disponibles:"
|
||
fi
|
||
fi
|
||
for i in "${!AVAILABLE_DISKS[@]}"; do
|
||
disk="/dev/${AVAILABLE_DISKS[$i]}"
|
||
size=$(lsblk -dpno SIZE "$disk" | tr -d ' ')
|
||
status="${DISK_RAID_STATUS[$i]}"
|
||
|
||
if [ -n "$status" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo -e " $((i+1)). ${AVAILABLE_DISKS[$i]} - $size ${RED}[IN USE: $status]${NC}"
|
||
else
|
||
echo -e " $((i+1)). ${AVAILABLE_DISKS[$i]} - $size ${RED}[EN USO: $status]${NC}"
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " $((i+1)). ${AVAILABLE_DISKS[$i]} - $size [FREE]"
|
||
else
|
||
echo " $((i+1)). ${AVAILABLE_DISKS[$i]} - $size [LIBRE]"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
if [ ${#SELECTED_DISKS[@]} -gt 0 ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "✅ Selected disks (${#SELECTED_DISKS[@]}/${#AVAILABLE_DISKS[@]}): ${SELECTED_DISKS[*]}"
|
||
else
|
||
echo "✅ Discos seleccionados (${#SELECTED_DISKS[@]}/${#AVAILABLE_DISKS[@]}): ${SELECTED_DISKS[*]}"
|
||
fi
|
||
|
||
# Mostrar vista previa de la configuración RAID
|
||
show_raid_preview "$RAID_TYPE" "${SELECTED_DISKS[@]}"
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "⭕ Selected disks: none"
|
||
else
|
||
echo "⭕ Discos seleccionados: ninguno"
|
||
fi
|
||
fi
|
||
echo ""
|
||
|
||
# Show available commands reminder
|
||
if [ ${#SELECTED_DISKS[@]} -ge $min_disks ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 AVAILABLE COMMANDS:"
|
||
echo " • 'done' - Finish selection and continue"
|
||
echo " • 'clear' - Clear all selected disks"
|
||
echo " • Add more disks: Enter disk number (ex: 1, 2)"
|
||
echo " • Remove disks: Enter selected disk number again"
|
||
echo " • Use ranges: Enter range (ex: 1-2)"
|
||
else
|
||
echo "💡 COMANDOS DISPONIBLES:"
|
||
echo " • 'done' - Finalizar selección y continuar"
|
||
echo " • 'clear' - Limpiar todos los discos seleccionados"
|
||
echo " • Agregar más discos: Ingresa número de disco (ej: 1, 2)"
|
||
echo " • Quitar discos: Ingresa número de disco seleccionado otra vez"
|
||
echo " • Usar rangos: Ingresa rango (ej: 1-2)"
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 AVAILABLE COMMANDS:"
|
||
echo " • Enter disk numbers: Individual (ex: 3), multiple (ex: 3 4 5), ranges (ex: 3-6)"
|
||
echo " • 'clear' - Reset selection"
|
||
echo " • Need minimum $min_disks disks to continue"
|
||
else
|
||
echo "💡 COMANDOS DISPONIBLES:"
|
||
echo " • Ingresa números de disco: Individual (ej: 3), múltiple (ej: 3 4 5), rangos (ej: 3-6)"
|
||
echo " • 'clear' - Resetear selección"
|
||
echo " • Se necesitan mínimo $min_disks discos para continuar"
|
||
fi
|
||
fi
|
||
echo ""
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
read -p "👉 Selection: " choice
|
||
else
|
||
read -p "👉 Selección: " choice
|
||
fi
|
||
|
||
if [ "$choice" = "done" ]; then
|
||
if [ ${#SELECTED_DISKS[@]} -ge $min_disks ]; then
|
||
break
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "❌ You need at least $min_disks disks for this RAID"
|
||
else
|
||
show_error "❌ Necesitas al menos $min_disks discos para este RAID"
|
||
fi
|
||
fi
|
||
elif [ "$choice" = "clear" ]; then
|
||
SELECTED_DISKS=()
|
||
SELECTED_DISK_SIZES=()
|
||
DISKS_TO_CLEAN=()
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "🧹 Selection cleared"
|
||
else
|
||
show_message "🧹 Selección limpiada"
|
||
fi
|
||
elif [[ "$choice" =~ ^[0-9]+(-[0-9]+)?$ ]]; then
|
||
# Manejar rangos (ej: 3-6)
|
||
if [[ "$choice" =~ - ]]; then
|
||
local start=$(echo "$choice" | cut -d'-' -f1)
|
||
local end=$(echo "$choice" | cut -d'-' -f2)
|
||
|
||
if [ "$start" -ge 1 ] && [ "$end" -le ${#AVAILABLE_DISKS[@]} ] && [ "$start" -le "$end" ]; then
|
||
for ((i=start; i<=end; i++)); do
|
||
local disk_index=$((i-1))
|
||
local disk="${AVAILABLE_DISKS[$disk_index]}"
|
||
local disk_status="${DISK_RAID_STATUS[$disk_index]}"
|
||
|
||
# Procesar disco (similar a la lógica individual)
|
||
if [[ ! " ${SELECTED_DISKS[*]} " =~ " ${disk} " ]]; then
|
||
if [ -n "$disk_status" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ Disk $disk is in use: $disk_status"
|
||
if confirm "Clean $disk and add it?"; then
|
||
SELECTED_DISKS+=("$disk")
|
||
disk_size=$(lsblk -dpno SIZE "/dev/$disk" --bytes)
|
||
SELECTED_DISK_SIZES+=("$disk_size")
|
||
DISKS_TO_CLEAN+=("$disk")
|
||
fi
|
||
else
|
||
show_warning "⚠️ Disco $disk está en uso: $disk_status"
|
||
if confirm "¿Limpiar $disk y agregarlo?"; then
|
||
SELECTED_DISKS+=("$disk")
|
||
disk_size=$(lsblk -dpno SIZE "/dev/$disk" --bytes)
|
||
SELECTED_DISK_SIZES+=("$disk_size")
|
||
DISKS_TO_CLEAN+=("$disk")
|
||
fi
|
||
fi
|
||
else
|
||
SELECTED_DISKS+=("$disk")
|
||
disk_size=$(lsblk -dpno SIZE "/dev/$disk" --bytes)
|
||
SELECTED_DISK_SIZES+=("$disk_size")
|
||
fi
|
||
fi
|
||
done
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ Processed range $start-$end"
|
||
else
|
||
show_message "✅ Procesado rango $start-$end"
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "❌ Invalid range. Use format: start-end (ex: 3-6)"
|
||
else
|
||
echo "❌ Rango inválido. Usa formato: inicio-fin (ej: 3-6)"
|
||
fi
|
||
fi
|
||
else
|
||
# Selección individual (lógica original)
|
||
if [ "$choice" -ge 1 ] && [ "$choice" -le ${#AVAILABLE_DISKS[@]} ]; then
|
||
disk_index=$((choice-1))
|
||
disk="${AVAILABLE_DISKS[$disk_index]}"
|
||
disk_status="${DISK_RAID_STATUS[$disk_index]}"
|
||
|
||
# Verificar si ya está seleccionado
|
||
if [[ " ${SELECTED_DISKS[*]} " =~ " ${disk} " ]]; then
|
||
# Quitar de la selección
|
||
new_selected=()
|
||
new_sizes=()
|
||
new_to_clean=()
|
||
for i in "${!SELECTED_DISKS[@]}"; do
|
||
if [ "${SELECTED_DISKS[$i]}" != "$disk" ]; then
|
||
new_selected+=("${SELECTED_DISKS[$i]}")
|
||
new_sizes+=("${SELECTED_DISK_SIZES[$i]}")
|
||
fi
|
||
done
|
||
SELECTED_DISKS=("${new_selected[@]}")
|
||
SELECTED_DISK_SIZES=("${new_sizes[@]}")
|
||
# Remover de discos a limpiar si estaba ahí
|
||
for i in "${!DISKS_TO_CLEAN[@]}"; do
|
||
if [ "${DISKS_TO_CLEAN[$i]}" != "$disk" ]; then
|
||
new_to_clean+=("${DISKS_TO_CLEAN[$i]}")
|
||
fi
|
||
done
|
||
DISKS_TO_CLEAN=("${new_to_clean[@]}")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "➖ Removed: $disk"
|
||
else
|
||
show_message "➖ Removido: $disk"
|
||
fi
|
||
else
|
||
# Verificar si el disco está en uso
|
||
if [ -n "$disk_status" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ Disk $disk is in use: $disk_status"
|
||
show_warning "⚠️ If you continue, this disk will be completely cleaned and ALL data will be lost."
|
||
|
||
if confirm "Do you want to clean this disk and use it for the new RAID?"; then
|
||
SELECTED_DISKS+=("$disk")
|
||
disk_size=$(lsblk -dpno SIZE "/dev/$disk" --bytes)
|
||
SELECTED_DISK_SIZES+=("$disk_size")
|
||
DISKS_TO_CLEAN+=("$disk")
|
||
show_message "✅ Added (will be cleaned): $disk"
|
||
else
|
||
show_message "❌ Disk $disk not selected"
|
||
fi
|
||
else
|
||
show_warning "⚠️ El disco $disk está en uso: $disk_status"
|
||
show_warning "⚠️ Si continúas, este disco será completamente limpiado y se perderán TODOS los datos."
|
||
|
||
if confirm "¿Deseas limpiar este disco y usarlo para el nuevo RAID?"; then
|
||
SELECTED_DISKS+=("$disk")
|
||
disk_size=$(lsblk -dpno SIZE "/dev/$disk" --bytes)
|
||
SELECTED_DISK_SIZES+=("$disk_size")
|
||
DISKS_TO_CLEAN+=("$disk")
|
||
show_message "✅ Agregado (se limpiará): $disk"
|
||
else
|
||
show_message "❌ Disco $disk no seleccionado"
|
||
fi
|
||
fi
|
||
else
|
||
# Agregar a la selección (disco libre)
|
||
SELECTED_DISKS+=("$disk")
|
||
disk_size=$(lsblk -dpno SIZE "/dev/$disk" --bytes)
|
||
SELECTED_DISK_SIZES+=("$disk_size")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ Added: $disk"
|
||
else
|
||
show_message "✅ Agregado: $disk"
|
||
fi
|
||
fi
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "❌ Invalid number. Use 1-${#AVAILABLE_DISKS[@]}"
|
||
else
|
||
echo "❌ Número inválido. Usa 1-${#AVAILABLE_DISKS[@]}"
|
||
fi
|
||
fi
|
||
fi
|
||
elif [[ "$choice" =~ ^[0-9\ ]+$ ]]; then
|
||
# Manejar múltiples números separados por espacios (ej: 3 4 5 6)
|
||
for num in $choice; do
|
||
if [ "$num" -ge 1 ] && [ "$num" -le ${#AVAILABLE_DISKS[@]} ]; then
|
||
disk_index=$((num-1))
|
||
disk="${AVAILABLE_DISKS[$disk_index]}"
|
||
disk_status="${DISK_RAID_STATUS[$disk_index]}"
|
||
|
||
if [[ ! " ${SELECTED_DISKS[*]} " =~ " ${disk} " ]]; then
|
||
if [ -n "$disk_status" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "⚠️ Disk $disk is in use: $disk_status"
|
||
if confirm "Clean $disk and add it?"; then
|
||
SELECTED_DISKS+=("$disk")
|
||
disk_size=$(lsblk -dpno SIZE "/dev/$disk" --bytes)
|
||
SELECTED_DISK_SIZES+=("$disk_size")
|
||
DISKS_TO_CLEAN+=("$disk")
|
||
show_message "✅ Added (will be cleaned): $disk"
|
||
fi
|
||
else
|
||
show_warning "⚠️ Disco $disk está en uso: $disk_status"
|
||
if confirm "¿Limpiar $disk y agregarlo?"; then
|
||
SELECTED_DISKS+=("$disk")
|
||
disk_size=$(lsblk -dpno SIZE "/dev/$disk" --bytes)
|
||
SELECTED_DISK_SIZES+=("$disk_size")
|
||
DISKS_TO_CLEAN+=("$disk")
|
||
show_message "✅ Agregado (se limpiará): $disk"
|
||
fi
|
||
fi
|
||
else
|
||
SELECTED_DISKS+=("$disk")
|
||
disk_size=$(lsblk -dpno SIZE "/dev/$disk" --bytes)
|
||
SELECTED_DISK_SIZES+=("$disk_size")
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ Added: $disk"
|
||
else
|
||
show_message "✅ Agregado: $disk"
|
||
fi
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "ℹ️ $disk was already selected"
|
||
else
|
||
show_message "ℹ️ $disk ya estaba seleccionado"
|
||
fi
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "❌ Invalid number: $num (use 1-${#AVAILABLE_DISKS[@]})"
|
||
else
|
||
echo "❌ Número inválido: $num (usa 1-${#AVAILABLE_DISKS[@]})"
|
||
fi
|
||
fi
|
||
done
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Invalid option"
|
||
else
|
||
echo "Opción inválida"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Si hay discos para limpiar, mostrar resumen y confirmar
|
||
if [ ${#DISKS_TO_CLEAN[@]} -gt 0 ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "SUMMARY OF DISKS TO CLEAN:"
|
||
else
|
||
show_warning "RESUMEN DE DISCOS A LIMPIAR:"
|
||
fi
|
||
for disk in "${DISKS_TO_CLEAN[@]}"; do
|
||
# Encontrar el índice del disco para mostrar su estado
|
||
for i in "${!AVAILABLE_DISKS[@]}"; do
|
||
if [ "${AVAILABLE_DISKS[$i]}" = "$disk" ]; then
|
||
echo -e " - $disk: ${DISK_RAID_STATUS[$i]}"
|
||
break
|
||
fi
|
||
done
|
||
done
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "ALL DATA ON THESE DISKS WILL BE PERMANENTLY LOST!"
|
||
|
||
if ! confirm "Are you completely sure you want to continue?"; then
|
||
show_message "Operation cancelled by user"
|
||
exit 0
|
||
fi
|
||
else
|
||
show_warning "¡TODOS LOS DATOS EN ESTOS DISCOS SE PERDERÁN PERMANENTEMENTE!"
|
||
|
||
if ! confirm "¿Estás completamente seguro de que deseas continuar?"; then
|
||
show_message "Operación cancelada por el usuario"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
# Proceder con la limpieza
|
||
for disk in "${DISKS_TO_CLEAN[@]}"; do
|
||
clean_disk "$disk"
|
||
done
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "All disks have been cleaned successfully"
|
||
else
|
||
show_message "Todos los discos han sido limpiados exitosamente"
|
||
fi
|
||
fi
|
||
|
||
# Calcular capacidad del RAID
|
||
calculate_raid_capacity "$RAID_TYPE" "${SELECTED_DISK_SIZES[@]}"
|
||
}
|
||
|
||
# Función para configurar BTRFS
|
||
setup_btrfs() {
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Configuring BTRFS RAID"
|
||
else
|
||
show_title "Configurando BTRFS RAID"
|
||
fi
|
||
|
||
# Seleccionar tipo de RAID
|
||
show_raid_types
|
||
while true; do
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
read -p "Select RAID type (1-5): " choice
|
||
else
|
||
read -p "Selecciona el tipo de RAID (1-5): " choice
|
||
fi
|
||
case $choice in
|
||
1) RAID_TYPE="raid0"; break;;
|
||
2) RAID_TYPE="raid1"; break;;
|
||
3) RAID_TYPE="raid5";
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "RAID 5 is experimental in BTRFS"
|
||
if confirm "Do you want to continue?"; then break; else continue; fi
|
||
else
|
||
show_warning "RAID 5 es experimental en BTRFS"
|
||
if confirm "¿Deseas continuar?"; then break; else continue; fi
|
||
fi;;
|
||
4) RAID_TYPE="raid6";
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning "RAID 6 is experimental in BTRFS"
|
||
if confirm "Do you want to continue?"; then break; else continue; fi
|
||
else
|
||
show_warning "RAID 6 es experimental en BTRFS"
|
||
if confirm "¿Deseas continuar?"; then break; else continue; fi
|
||
fi;;
|
||
5) RAID_TYPE="raid10"; break;;
|
||
*)
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Invalid option"
|
||
else
|
||
echo "Opción inválida"
|
||
fi;;
|
||
esac
|
||
done
|
||
|
||
select_disks
|
||
|
||
# Solicitar punto de montaje
|
||
read -p "Ingresa la ruta donde quieres montar el RAID (ej: /mnt/raid): " MOUNT_POINT
|
||
|
||
if [ ! -d "$MOUNT_POINT" ]; then
|
||
if confirm "El directorio $MOUNT_POINT no existe. ¿Deseas crearlo?"; then
|
||
sudo mkdir -p "$MOUNT_POINT"
|
||
show_message "Directorio $MOUNT_POINT creado"
|
||
else
|
||
show_error "Se necesita un punto de montaje válido"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
# Crear el filesystem BTRFS
|
||
show_message "Creando filesystem BTRFS..."
|
||
|
||
device_list=""
|
||
for disk in "${SELECTED_DISKS[@]}"; do
|
||
device_list="$device_list /dev/$disk"
|
||
done
|
||
|
||
sudo mkfs.btrfs -f -d "$RAID_TYPE" -m "$RAID_TYPE" $device_list
|
||
|
||
# Montar el filesystem
|
||
sudo mount "/dev/${SELECTED_DISKS[0]}" "$MOUNT_POINT"
|
||
|
||
show_message "BTRFS RAID configurado exitosamente"
|
||
FILESYSTEM_UUID=$(sudo blkid -s UUID -o value "/dev/${SELECTED_DISKS[0]}")
|
||
}
|
||
|
||
# Función para obtener RAM del sistema
|
||
get_system_ram() {
|
||
local ram_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||
local ram_gb=$((ram_kb / 1024 / 1024))
|
||
echo $ram_gb
|
||
}
|
||
|
||
# Función para configurar ZFS
|
||
setup_zfs() {
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_title "Configuring ZFS RAID"
|
||
else
|
||
show_title "Configurando ZFS RAID"
|
||
fi
|
||
|
||
# Verificar que ZFS esté disponible (debería estarlo después de check_and_install_requirements)
|
||
if ! command -v zpool &> /dev/null; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "ZFS is not available. This should not happen after requirements verification."
|
||
else
|
||
show_error "ZFS no está disponible. Esto no debería suceder después de la verificación de requisitos."
|
||
fi
|
||
exit 1
|
||
fi
|
||
|
||
# Verificar que el módulo ZFS esté cargado
|
||
if ! lsmod | grep -q "^zfs "; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Loading ZFS module..."
|
||
else
|
||
show_message "Cargando módulo ZFS..."
|
||
fi
|
||
sudo modprobe zfs
|
||
sleep 2
|
||
|
||
if ! lsmod | grep -q "^zfs "; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "Could not load ZFS module"
|
||
else
|
||
show_error "No se pudo cargar el módulo ZFS"
|
||
fi
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
# Seleccionar tipo de RAID
|
||
show_raid_types
|
||
while true; do
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
read -p "Select RAID type (1-5): " choice
|
||
else
|
||
read -p "Selecciona el tipo de RAID (1-5): " choice
|
||
fi
|
||
case $choice in
|
||
1) RAID_TYPE="stripe"; break;;
|
||
2) RAID_TYPE="mirror"; break;;
|
||
3) RAID_TYPE="raidz1"; break;;
|
||
4) RAID_TYPE="raidz2"; break;;
|
||
5) RAID_TYPE="raidz3"; break;;
|
||
*) echo "Opción inválida";;
|
||
esac
|
||
done
|
||
|
||
select_disks
|
||
|
||
# Solicitar nombre del pool
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
read -p "Enter ZFS pool name: " POOL_NAME
|
||
else
|
||
read -p "Ingresa el nombre del pool ZFS: " POOL_NAME
|
||
fi
|
||
|
||
# Configurar ARC
|
||
local system_ram=$(get_system_ram)
|
||
local recommended_arc=$((system_ram / 4))
|
||
if [ $recommended_arc -lt 1 ]; then
|
||
recommended_arc=1
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "System RAM: ${system_ram}GB"
|
||
show_message "Recommended ARC: ${recommended_arc}GB"
|
||
|
||
read -p "How many GB do you want to assign to ARC? [$recommended_arc]: " arc_size
|
||
else
|
||
show_message "RAM del sistema: ${system_ram}GB"
|
||
show_message "ARC recomendado: ${recommended_arc}GB"
|
||
|
||
read -p "¿Cuántos GB quieres asignar al ARC? [$recommended_arc]: " arc_size
|
||
fi
|
||
arc_size=${arc_size:-$recommended_arc}
|
||
|
||
# Detectar ashift óptimo considerando compatibilidad futura
|
||
local optimal_ashift=12 # Default para compatibilidad con cache devices
|
||
local max_sector_size=512
|
||
local has_4k_sectors=false
|
||
|
||
# Detectar el tamaño de sector más grande entre los discos seleccionados
|
||
for disk in "${SELECTED_DISKS[@]}"; do
|
||
if [ -b "/dev/$disk" ]; then
|
||
local sector_size=$(sudo blockdev --getpbsz "/dev/$disk" 2>/dev/null)
|
||
if [ -n "$sector_size" ]; then
|
||
if [ "$sector_size" -gt "$max_sector_size" ]; then
|
||
max_sector_size=$sector_size
|
||
fi
|
||
if [ "$sector_size" -eq 4096 ]; then
|
||
has_4k_sectors=true
|
||
fi
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Estrategia de ashift optimizada para compatibilidad
|
||
if [ "$max_sector_size" -le 512 ] && [ "$has_4k_sectors" = false ]; then
|
||
# Solo discos 512-byte: usar ashift=12 por compatibilidad con cache futuro
|
||
optimal_ashift=12
|
||
show_message "[INFO] 🔧 Usando ashift=12 para compatibilidad con cache devices SSD"
|
||
else
|
||
# Calcular ashift basado en el tamaño de sector más grande
|
||
case $max_sector_size in
|
||
512) optimal_ashift=12 ;; # Forzar 12 para compatibilidad
|
||
1024) optimal_ashift=10 ;; # 2^10 = 1024 bytes
|
||
2048) optimal_ashift=11 ;; # 2^11 = 2048 bytes
|
||
4096) optimal_ashift=12 ;; # 2^12 = 4096 bytes (óptimo)
|
||
8192) optimal_ashift=13 ;; # 2^13 = 8192 bytes
|
||
*) optimal_ashift=12 ;; # Default seguro
|
||
esac
|
||
fi
|
||
|
||
show_message "$(get_text "sector_config_detected")"
|
||
show_message "$(get_text "max_sector_size_hdds") ${max_sector_size} bytes"
|
||
show_message "$(get_text "pool_ashift") ${optimal_ashift} (2^${optimal_ashift} = $((2**optimal_ashift)) bytes)"
|
||
show_message "$(get_text "compatibility_cache_devices")"
|
||
|
||
# Crear el pool ZFS
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Creating ZFS pool..."
|
||
else
|
||
show_message "Creando pool ZFS..."
|
||
fi
|
||
|
||
# Preparar discos (limpiar filesystems existentes)
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Preparing disks (wiping existing filesystems)..."
|
||
else
|
||
show_message "Preparando discos (limpiando filesystems existentes)..."
|
||
fi
|
||
|
||
for disk in "${SELECTED_DISKS[@]}"; do
|
||
clean_disk "$disk"
|
||
done
|
||
|
||
device_list=""
|
||
for disk in "${SELECTED_DISKS[@]}"; do
|
||
device_list="$device_list /dev/$disk"
|
||
done
|
||
|
||
case $RAID_TYPE in
|
||
"stripe")
|
||
sudo zpool create -f -o ashift=$optimal_ashift "$POOL_NAME" $device_list
|
||
;;
|
||
"mirror")
|
||
sudo zpool create -f -o ashift=$optimal_ashift "$POOL_NAME" mirror $device_list
|
||
;;
|
||
"raidz1")
|
||
sudo zpool create -f -o ashift=$optimal_ashift "$POOL_NAME" raidz $device_list
|
||
;;
|
||
"raidz2")
|
||
sudo zpool create -f -o ashift=$optimal_ashift "$POOL_NAME" raidz2 $device_list
|
||
;;
|
||
"raidz3")
|
||
sudo zpool create -f -o ashift=$optimal_ashift "$POOL_NAME" raidz3 $device_list
|
||
;;
|
||
esac
|
||
|
||
# Configurar ARC
|
||
echo $((arc_size * 1024 * 1024 * 1024)) | sudo tee /sys/module/zfs/parameters/zfs_arc_max > /dev/null
|
||
|
||
# Hacer persistente la configuración del ARC
|
||
sudo mkdir -p /etc/modprobe.d
|
||
echo "options zfs zfs_arc_max=$((arc_size * 1024 * 1024 * 1024))" | sudo tee /etc/modprobe.d/zfs.conf > /dev/null
|
||
|
||
MOUNT_POINT="/$POOL_NAME"
|
||
|
||
# Configurar NVME para cache y log si está disponible
|
||
if [ -n "$NVME_DISK" ] && [[ ! " ${SELECTED_DISKS[*]} " =~ " ${NVME_DISK} " ]]; then
|
||
if confirm "¿Deseas usar el NVME ($NVME_DISK) para ARC2 (L2ARC) y SLOG?"; then
|
||
show_message "Particionando NVME para cache y log..."
|
||
|
||
# Crear particiones en el NVME
|
||
sudo parted "/dev/$NVME_DISK" --script mklabel gpt
|
||
sudo parted "/dev/$NVME_DISK" --script mkpart primary 0% 50%
|
||
sudo parted "/dev/$NVME_DISK" --script mkpart primary 50% 100%
|
||
|
||
sleep 2
|
||
|
||
# Agregar cache y log al pool
|
||
sudo zpool add "$POOL_NAME" cache "/dev/${NVME_DISK}p1"
|
||
sudo zpool add "$POOL_NAME" log "/dev/${NVME_DISK}p2"
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "NVME configured as cache and log"
|
||
else
|
||
show_message "NVME configurado como cache y log"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "ZFS pool configured successfully"
|
||
else
|
||
show_message "ZFS pool configurado exitosamente"
|
||
fi
|
||
|
||
# Crear datasets dentro del pool principal usando la función reutilizable
|
||
echo ""
|
||
if confirm "¿Deseas crear datasets dentro del pool '$POOL_NAME'?"; then
|
||
create_datasets_in_pool "$POOL_NAME"
|
||
fi
|
||
|
||
# Preguntar por pools adicionales solo si hay discos restantes
|
||
remaining_disks=()
|
||
for disk in "${AVAILABLE_DISKS[@]}"; do
|
||
if [[ ! " ${SELECTED_DISKS[*]} " =~ " ${disk} " ]] && [ "$disk" != "$NVME_DISK" ]; then
|
||
# Verificar que el disco no sea demasiado pequeño (ignorar mmcblk0boot)
|
||
if [[ ! "$disk" =~ mmcblk.*boot ]]; then
|
||
remaining_disks+=("$disk")
|
||
fi
|
||
fi
|
||
done
|
||
|
||
if [ ${#remaining_disks[@]} -gt 0 ]; then
|
||
echo ""
|
||
show_message "Discos disponibles restantes:"
|
||
for disk in "${remaining_disks[@]}"; do
|
||
size=$(lsblk -dpno SIZE "/dev/$disk" | tr -d ' ')
|
||
model=$(lsblk -dpno MODEL "/dev/$disk" | tr -d ' ')
|
||
echo " - $disk ($size, $model)"
|
||
done
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 ADDITIONAL POOLS INFORMATION:"
|
||
else
|
||
echo "💡 INFORMACIÓN SOBRE POOLS ADICIONALES:"
|
||
fi
|
||
echo " Los pools adicionales son independientes del pool principal."
|
||
echo " Útiles para:"
|
||
echo " • Separar datos por uso (backup, cache, temp)"
|
||
echo " • Diferentes niveles de redundancia"
|
||
echo " • Optimizar rendimiento por tipo de carga"
|
||
echo ""
|
||
echo " Ejemplo: Pool principal para datos + Pool SSD para cache"
|
||
echo ""
|
||
|
||
if confirm "¿Deseas crear pools ZFS adicionales con los discos restantes?"; then
|
||
# Implementar creación de pools adicionales
|
||
while [ ${#remaining_disks[@]} -gt 0 ]; do
|
||
echo ""
|
||
show_title "Configuración de Pool Adicional"
|
||
|
||
read -p "Nombre del nuevo pool: " additional_pool_name
|
||
|
||
if [ -z "$additional_pool_name" ]; then
|
||
show_error "El nombre del pool no puede estar vacío"
|
||
continue
|
||
fi
|
||
|
||
# Verificar que el nombre no exista
|
||
if zpool list -H -o name 2>/dev/null | grep -q "^${additional_pool_name}$"; then
|
||
show_error "Ya existe un pool con el nombre '$additional_pool_name'"
|
||
continue
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Available disks for pool '$additional_pool_name':"
|
||
else
|
||
echo "Discos disponibles para el pool '$additional_pool_name':"
|
||
fi
|
||
for i in "${!remaining_disks[@]}"; do
|
||
disk="${remaining_disks[$i]}"
|
||
size=$(lsblk -dpno SIZE "/dev/$disk" | tr -d ' ')
|
||
model=$(lsblk -dpno MODEL "/dev/$disk" | tr -d ' ')
|
||
echo " $((i+1)). $disk - $size - $model"
|
||
done
|
||
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "Available RAID types:"
|
||
else
|
||
echo "Tipos de RAID disponibles:"
|
||
fi
|
||
echo "1. Stripe - Sin redundancia, máximo rendimiento"
|
||
echo "2. Mirror - Datos duplicados entre discos"
|
||
echo "3. RAIDZ1 - Un disco de paridad (mínimo 3 discos)"
|
||
echo "4. RAIDZ2 - Dos discos de paridad (mínimo 4 discos)"
|
||
|
||
read -p "Selecciona tipo de RAID (1-4): " raid_choice
|
||
|
||
local additional_raid_type=""
|
||
local min_disks_needed=1
|
||
|
||
case $raid_choice in
|
||
1) additional_raid_type="stripe"; min_disks_needed=1;;
|
||
2) additional_raid_type="mirror"; min_disks_needed=2;;
|
||
3) additional_raid_type="raidz1"; min_disks_needed=3;;
|
||
4) additional_raid_type="raidz2"; min_disks_needed=4;;
|
||
*)
|
||
show_error "Opción inválida"
|
||
continue
|
||
;;
|
||
esac
|
||
|
||
if [ ${#remaining_disks[@]} -lt $min_disks_needed ]; then
|
||
show_error "Se necesitan al menos $min_disks_needed discos para $additional_raid_type"
|
||
continue
|
||
fi
|
||
|
||
# Selección simple para pools adicionales
|
||
selected_additional_disks=()
|
||
echo ""
|
||
echo "Selecciona discos para '$additional_pool_name' (mínimo $min_disks_needed):"
|
||
echo "Ingresa números separados por espacios (ej: 1 2 3):"
|
||
|
||
read -p "Selección: " disk_selection
|
||
|
||
selected_additional_disks=()
|
||
for num in $disk_selection; do
|
||
if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le ${#remaining_disks[@]} ]; then
|
||
idx=$((num-1))
|
||
selected_additional_disks+=("${remaining_disks[$idx]}")
|
||
fi
|
||
done
|
||
|
||
if [ ${#selected_additional_disks[@]} -lt $min_disks_needed ]; then
|
||
show_error "Se necesitan al menos $min_disks_needed discos"
|
||
continue
|
||
fi
|
||
|
||
# Crear el pool adicional
|
||
show_message "Creando pool adicional '$additional_pool_name'..."
|
||
|
||
# Detectar ashift óptimo para el pool adicional
|
||
local additional_optimal_ashift=12 # Default para compatibilidad
|
||
local additional_max_sector_size=512
|
||
local additional_has_4k_sectors=false
|
||
|
||
# Detectar el tamaño de sector más grande entre los discos seleccionados
|
||
for disk in "${selected_additional_disks[@]}"; do
|
||
if [ -b "/dev/$disk" ]; then
|
||
local sector_size=$(sudo blockdev --getpbsz "/dev/$disk" 2>/dev/null)
|
||
if [ -n "$sector_size" ]; then
|
||
if [ "$sector_size" -gt "$additional_max_sector_size" ]; then
|
||
additional_max_sector_size=$sector_size
|
||
fi
|
||
if [ "$sector_size" -eq 4096 ]; then
|
||
additional_has_4k_sectors=true
|
||
fi
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Estrategia de ashift optimizada para compatibilidad
|
||
if [ "$additional_max_sector_size" -le 512 ] && [ "$additional_has_4k_sectors" = false ]; then
|
||
# Solo discos 512-byte: usar ashift=12 por compatibilidad
|
||
additional_optimal_ashift=12
|
||
show_message "[INFO] 🔧 Usando ashift=12 para compatibilidad con cache devices"
|
||
else
|
||
# Calcular ashift basado en el tamaño de sector más grande
|
||
case $additional_max_sector_size in
|
||
512) additional_optimal_ashift=12 ;; # Forzar 12 para compatibilidad
|
||
1024) additional_optimal_ashift=10 ;;
|
||
2048) additional_optimal_ashift=11 ;;
|
||
4096) additional_optimal_ashift=12 ;;
|
||
8192) additional_optimal_ashift=13 ;;
|
||
*) additional_optimal_ashift=12 ;;
|
||
esac
|
||
fi
|
||
|
||
show_message "$(get_text "config_for_pool") '$additional_pool_name':"
|
||
show_message "$(get_text "max_sector_size_hdds") ${additional_max_sector_size} bytes"
|
||
show_message "$(get_text "pool_ashift") ${additional_optimal_ashift} (2^${additional_optimal_ashift} = $((2**additional_optimal_ashift)) bytes)"
|
||
show_message "$(get_text "ensures_compatibility_future")"
|
||
|
||
# Limpiar discos seleccionados antes de crear el pool
|
||
for disk in "${selected_additional_disks[@]}"; do
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "🧹 Cleaning disk /dev/$disk before using it..."
|
||
else
|
||
show_message "🧹 Limpiando disco /dev/$disk antes de usarlo..."
|
||
fi
|
||
clean_disk "$disk"
|
||
done
|
||
|
||
local device_list=""
|
||
for disk in "${selected_additional_disks[@]}"; do
|
||
device_list="$device_list /dev/$disk"
|
||
done
|
||
|
||
case $additional_raid_type in
|
||
"stripe")
|
||
sudo zpool create -f -o ashift=$additional_optimal_ashift "$additional_pool_name" $device_list
|
||
;;
|
||
"mirror")
|
||
sudo zpool create -f -o ashift=$additional_optimal_ashift "$additional_pool_name" mirror $device_list
|
||
;;
|
||
"raidz1")
|
||
sudo zpool create -f -o ashift=$additional_optimal_ashift "$additional_pool_name" raidz $device_list
|
||
;;
|
||
"raidz2")
|
||
sudo zpool create -f -o ashift=$additional_optimal_ashift "$additional_pool_name" raidz2 $device_list
|
||
;;
|
||
esac
|
||
|
||
if [ $? -eq 0 ]; then
|
||
show_message "✅ Pool '$additional_pool_name' creado exitosamente"
|
||
|
||
# Remover discos usados de la lista de disponibles
|
||
new_remaining=()
|
||
for disk in "${remaining_disks[@]}"; do
|
||
if [[ ! " ${selected_additional_disks[*]} " =~ " ${disk} " ]]; then
|
||
new_remaining+=("$disk")
|
||
fi
|
||
done
|
||
remaining_disks=("${new_remaining[@]}")
|
||
|
||
if [ ${#remaining_disks[@]} -eq 0 ]; then
|
||
show_message "No quedan más discos disponibles"
|
||
break
|
||
fi
|
||
|
||
if ! confirm "¿Crear otro pool adicional?"; then
|
||
break
|
||
fi
|
||
else
|
||
show_error "❌ Error creando el pool '$additional_pool_name'"
|
||
fi
|
||
done
|
||
fi
|
||
else
|
||
show_message "ℹ️ No hay discos adicionales disponibles para más pools"
|
||
fi
|
||
}
|
||
|
||
# Función para mostrar resumen
|
||
show_summary() {
|
||
show_title "Resumen de Configuración"
|
||
|
||
echo "Sistema de archivos: $FILESYSTEM_TYPE"
|
||
echo "Tipo de RAID: $RAID_TYPE"
|
||
echo "Discos utilizados: ${SELECTED_DISKS[*]}"
|
||
echo "Punto de montaje: $MOUNT_POINT"
|
||
|
||
if [ "$FILESYSTEM_TYPE" = "zfs" ]; then
|
||
echo "Nombre del pool: $POOL_NAME"
|
||
echo "ARC configurado: ${arc_size}GB"
|
||
fi
|
||
|
||
local raid_capacity_gb=$(( RAID_CAPACITY / 1024 / 1024 / 1024 ))
|
||
local raid_capacity_formatted=$(format_capacity "$raid_capacity_gb")
|
||
echo "Capacidad aproximada del RAID: ${raid_capacity_formatted}"
|
||
}
|
||
|
||
# Función para configurar montaje automático
|
||
setup_auto_mount() {
|
||
if confirm "¿Deseas montar automáticamente al iniciar el sistema?"; then
|
||
if [ "$FILESYSTEM_TYPE" = "btrfs" ]; then
|
||
# Agregar entrada a /etc/fstab para BTRFS
|
||
echo "UUID=$FILESYSTEM_UUID $MOUNT_POINT btrfs defaults 0 0" | sudo tee -a /etc/fstab
|
||
show_message "Montaje automático configurado en /etc/fstab"
|
||
else
|
||
# Para ZFS, habilitar el servicio de importación automática
|
||
sudo systemctl enable zfs-import-cache
|
||
sudo systemctl enable zfs-mount
|
||
sudo systemctl enable zfs.target
|
||
show_message "Servicios ZFS habilitados para montaje automático"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# Función principal
|
||
main() {
|
||
# Select language first / Seleccionar idioma primero
|
||
select_language
|
||
|
||
show_title "$(get_text "script_title")"
|
||
|
||
# Check if running as root or with sudo / Verificar si se ejecuta como root o con sudo
|
||
if [ "$EUID" -eq 0 ]; then
|
||
show_error "$(get_text "root_warning")"
|
||
exit 1
|
||
fi
|
||
|
||
# Check and install requirements / Verificar e instalar requisitos
|
||
check_and_install_requirements
|
||
|
||
# Detect existing RAID configurations (ZFS, BTRFS, MDADM, LVM)
|
||
# Detectar configuraciones RAID existentes (ZFS, BTRFS, MDADM, LVM)
|
||
if detect_existing_raid_configurations; then
|
||
# Continue with normal configuration / Continúa con configuración normal
|
||
detect_disks
|
||
select_filesystem
|
||
|
||
if [ "$FILESYSTEM_TYPE" = "btrfs" ]; then
|
||
setup_btrfs
|
||
else
|
||
setup_zfs
|
||
fi
|
||
|
||
show_summary
|
||
setup_auto_mount
|
||
|
||
show_message "$(get_text "raid_completed")"
|
||
show_message "$(get_text "raid_mounted_at") $MOUNT_POINT"
|
||
|
||
# Offer dataset management after creating the pool
|
||
# Ofrecer gestión de datasets después de crear el pool
|
||
offer_post_creation_dataset_management
|
||
fi
|
||
# If detected existing RAID configurations and user chose to manage them,
|
||
# the detect_existing_raid_configurations function already handled everything
|
||
# Si detectó configuraciones RAID existentes y el usuario eligió gestionarlas,
|
||
# la función detect_existing_raid_configurations ya manejó todo
|
||
}
|
||
|
||
# Función para ofrecer gestión de datasets después de crear un pool
|
||
offer_post_creation_dataset_management() {
|
||
if [ "$FILESYSTEM_TYPE" = "zfs" ] && [ -n "$POOL_NAME" ]; then
|
||
echo ""
|
||
show_title "Gestión Post-Creación"
|
||
echo ""
|
||
echo "🎉 ¡Pool ZFS '$POOL_NAME' creado exitosamente!"
|
||
echo ""
|
||
|
||
# Configurar atime primero (recomendado)
|
||
configure_atime_settings "$POOL_NAME"
|
||
|
||
while true; do
|
||
echo ""
|
||
echo "🛠️ OPCIONES ADICIONALES:"
|
||
echo " 1. 🚀 Configurar dispositivos de cache (L2ARC/SLOG) - RECOMENDADO"
|
||
echo " 2. 📁 Gestionar datasets en '$POOL_NAME'"
|
||
echo " 3. 📸 Crear snapshots iniciales"
|
||
echo " 4. 📊 Ver estado completo del pool"
|
||
echo " 5. ⚙️ Reconfigurar atime"
|
||
echo " 6. ✅ Finalizar"
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 NOTE: Cache devices (option 1) must be SSD or NVMe"
|
||
else
|
||
echo "💡 NOTA: Los dispositivos de cache (opción 1) deben ser SSD o NVMe"
|
||
fi
|
||
echo " ⚠️ NO usar discos mecánicos - pueden empeorar el rendimiento"
|
||
echo ""
|
||
|
||
read -p "👉 Selecciona una opción (1-6): " choice
|
||
case $choice in
|
||
1)
|
||
echo ""
|
||
setup_cache_devices "$POOL_NAME"
|
||
;;
|
||
2)
|
||
echo ""
|
||
create_datasets_in_pool "$POOL_NAME"
|
||
;;
|
||
3)
|
||
create_initial_snapshots "$POOL_NAME"
|
||
;;
|
||
4)
|
||
if [ -z "$POOL_NAME" ]; then
|
||
show_error "Error: POOL_NAME no está definido. Esto no debería ocurrir."
|
||
echo "Información de debug:"
|
||
echo " FILESYSTEM_TYPE: $FILESYSTEM_TYPE"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " Available pools: $(zpool list -H -o name 2>/dev/null | tr '\n' ' ')"
|
||
else
|
||
echo " Pools disponibles: $(zpool list -H -o name 2>/dev/null | tr '\n' ' ')"
|
||
fi
|
||
read -p "Presiona Enter para continuar..."
|
||
else
|
||
show_pool_status "$POOL_NAME"
|
||
fi
|
||
;;
|
||
5)
|
||
echo ""
|
||
configure_atime_settings "$POOL_NAME"
|
||
;;
|
||
6)
|
||
show_message "¡Configuración completada!"
|
||
echo ""
|
||
echo "📊 RESUMEN FINAL:"
|
||
echo " Pool ZFS: $POOL_NAME"
|
||
echo " Estado: $(zpool list -H -o health "$POOL_NAME" 2>/dev/null || echo 'Desconocido')"
|
||
echo " Tamaño: $(zpool list -H -o size "$POOL_NAME" 2>/dev/null || echo 'Desconocido')"
|
||
echo " Usado: $(zpool list -H -o alloc "$POOL_NAME" 2>/dev/null || echo 'Desconocido')"
|
||
echo " Libre: $(zpool list -H -o free "$POOL_NAME" 2>/dev/null || echo 'Desconocido')"
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "✅ ZFS RAID configuration completed successfully!"
|
||
else
|
||
echo "✅ Configuración de RAID ZFS completada exitosamente!"
|
||
fi
|
||
break
|
||
;;
|
||
*)
|
||
echo "❌ Opción inválida. Selecciona 1, 2, 3, 4, 5 o 6."
|
||
;;
|
||
esac
|
||
echo ""
|
||
done
|
||
fi
|
||
|
||
# Asegurar que las variables estén definidas para evitar errores
|
||
if [ -z "$POOL_NAME" ] && [ "$FILESYSTEM_TYPE" = "zfs" ]; then
|
||
echo "⚠️ ADVERTENCIA: POOL_NAME no está definido al final de la gestión post-creación."
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " This could indicate a problem in the script."
|
||
else
|
||
echo " Esto podría indicar un problema en el script."
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# Función para configurar atime en ZFS
|
||
configure_atime_settings() {
|
||
local pool_name="$1"
|
||
|
||
show_title "Configuración de Atime en ZFS"
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 ATIME INFORMATION:"
|
||
else
|
||
echo "💡 INFORMACIÓN SOBRE ATIME:"
|
||
fi
|
||
echo " atime (access time) registra la última vez que se accedió a un archivo."
|
||
echo " En sistemas con muchas operaciones de lectura, puede impactar el rendimiento."
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "📊 AVAILABLE OPTIONS IN ZFS:"
|
||
else
|
||
echo "📊 OPCIONES DISPONIBLES EN ZFS:"
|
||
fi
|
||
echo " 1. off - No registrar atime (RECOMENDADO para rendimiento)"
|
||
echo " 2. on - Registrar atime completo (puede reducir rendimiento)"
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 RECOMMENDATION: Option 1 (off) for maximum performance"
|
||
else
|
||
echo "💡 RECOMENDACIÓN: Opción 1 (off) para máximo rendimiento"
|
||
fi
|
||
echo " ⚠️ NOTA: ZFS solo soporta 'on' u 'off' (no soporta 'relatime')"
|
||
echo " La mayoría de aplicaciones no necesitan atime y deshabilitarlo"
|
||
echo " mejora significativamente el rendimiento de lectura."
|
||
echo ""
|
||
|
||
while true; do
|
||
read -p "👉 Selecciona configuración de atime (1-2) [1]: " atime_choice
|
||
atime_choice=${atime_choice:-1}
|
||
|
||
case $atime_choice in
|
||
1)
|
||
local atime_setting="off"
|
||
local description="Deshabilitado (máximo rendimiento)"
|
||
break
|
||
;;
|
||
2)
|
||
local atime_setting="on"
|
||
local description="Habilitado (impacto en rendimiento)"
|
||
break
|
||
;;
|
||
*)
|
||
echo "❌ Opción inválida. Selecciona 1 o 2."
|
||
;;
|
||
esac
|
||
done
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Configuring atime=$atime_setting on pool '$pool_name'..."
|
||
else
|
||
show_message "Configurando atime=$atime_setting en el pool '$pool_name'..."
|
||
fi
|
||
|
||
# Aplicar configuración al pool raíz
|
||
if sudo zfs set atime="$atime_setting" "$pool_name"; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "✅ atime configured as '$atime_setting' on '$pool_name'"
|
||
else
|
||
show_message "✅ atime configurado como '$atime_setting' en '$pool_name'"
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_error "❌ Error configuring atime on '$pool_name'"
|
||
else
|
||
show_error "❌ Error configurando atime en '$pool_name'"
|
||
fi
|
||
return 1
|
||
fi
|
||
|
||
# Aplicar a todos los datasets existentes
|
||
local datasets=$(zfs list -H -o name -r "$pool_name" 2>/dev/null | grep -v "^${pool_name}$")
|
||
if [ -n "$datasets" ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message "Applying configuration to existing datasets..."
|
||
else
|
||
show_message "Aplicando configuración a datasets existentes..."
|
||
fi
|
||
for dataset in $datasets; do
|
||
if sudo zfs set atime="$atime_setting" "$dataset"; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_message " ✅ $dataset configured"
|
||
else
|
||
show_message " ✅ $dataset configurado"
|
||
fi
|
||
else
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
show_warning " ⚠️ Error configuring $dataset"
|
||
else
|
||
show_warning " ⚠️ Error configurando $dataset"
|
||
fi
|
||
fi
|
||
done
|
||
fi
|
||
|
||
echo ""
|
||
show_message "📊 CONFIGURACIÓN ATIME COMPLETADA:"
|
||
echo " Pool: $pool_name"
|
||
echo " Configuración: $atime_setting ($description)"
|
||
echo " Aplicado a: pool y todos los datasets existentes"
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 Note: New datasets will automatically inherit this configuration"
|
||
else
|
||
echo "💡 Nota: Los nuevos datasets heredarán esta configuración automáticamente"
|
||
fi
|
||
}
|
||
|
||
# Función para configurar dispositivos de cache (L2ARC y SLOG)
|
||
setup_cache_devices() {
|
||
local pool_name="$1"
|
||
|
||
show_title "Configuración de Dispositivos de Cache para '$pool_name'"
|
||
echo ""
|
||
echo "⚠️ ADVERTENCIA CRÍTICA SOBRE DISPOSITIVOS DE CACHE:"
|
||
echo " 🔥 SOLO USAR SSD O NVME - NUNCA DISCOS MECÁNICOS"
|
||
echo " 🚫 Los discos mecánicos (HDD) como cache EMPEORARÁN el rendimiento"
|
||
echo " ✅ Los dispositivos de cache deben ser MÁS RÁPIDOS que el almacenamiento principal"
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 CACHE DEVICES INFORMATION:"
|
||
else
|
||
echo "💡 INFORMACIÓN SOBRE DISPOSITIVOS DE CACHE:"
|
||
fi
|
||
echo ""
|
||
echo "🚀 L2ARC (Level 2 Adaptive Replacement Cache):"
|
||
echo " • Cache de segundo nivel para lecturas frecuentes"
|
||
echo " • Ideal: SSD rápido (NVMe > SATA SSD > USB 3.0)"
|
||
echo " • Mejora rendimiento de lectura en datasets accedidos frecuentemente"
|
||
echo " • No es crítico - si falla, el pool sigue funcionando"
|
||
echo ""
|
||
echo "📝 SLOG (Separate Intent Log):"
|
||
echo " • Log de transacciones para escrituras síncronas"
|
||
echo " • Ideal: SSD con baja latencia y alta resistencia (NVMe con power-loss protection)"
|
||
echo " • Mejora rendimiento de escrituras síncronas (bases de datos, VMs)"
|
||
echo " • Crítico para integridad - usar dispositivos confiables"
|
||
echo ""
|
||
echo "⚠️ RECOMENDACIÓN IMPORTANTE:"
|
||
echo " 🔥 USAR DISPOSITIVOS NVME ES ALTAMENTE RECOMENDADO PARA CACHE"
|
||
echo " • NVMe ofrece la latencia más baja y mayor throughput"
|
||
echo " • Usar dispositivos lentos (USB, HDD) como cache puede EMPEORAR el rendimiento"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " • If you don't have NVMe available, consider skipping cache configuration"
|
||
else
|
||
echo " • Si no tienes NVMe disponible, considera omitir la configuración de cache"
|
||
fi
|
||
echo ""
|
||
|
||
# Detectar dispositivos disponibles con clasificación por tipo
|
||
local pool_devices=$(zpool status "$pool_name" 2>/dev/null | grep -E "^\s+[a-z]" | awk '{print $1}' | grep -v "raidz\|mirror\|spare\|log\|cache\|replacing")
|
||
local available_cache_devices=()
|
||
local nvme_devices=()
|
||
local ssd_devices=()
|
||
local other_devices=()
|
||
|
||
# Obtener lista de todos los discos disponibles y clasificarlos
|
||
local available_cache_devices=()
|
||
local nvme_devices=()
|
||
local ssd_devices=()
|
||
local other_devices=()
|
||
local in_use_devices=()
|
||
|
||
while IFS= read -r disk; do
|
||
local disk_name=$(basename "$disk")
|
||
|
||
# Excluir dispositivos del sistema y de arranque
|
||
if [[ "$disk_name" == "mmcblk0"* ]] || [[ "$disk_name" == *"boot"* ]]; then
|
||
continue
|
||
fi
|
||
|
||
# Verificar que el dispositivo tenga tamaño válido
|
||
local size_raw=$(lsblk -dpno SIZE "/dev/$disk_name" 2>/dev/null | tr -d ' ')
|
||
if [[ "$size_raw" == "0B" ]] || [[ -z "$size_raw" ]]; then
|
||
continue
|
||
fi
|
||
|
||
# Verificar que no sea el disco del sistema operativo
|
||
local mount_check=$(lsblk -no MOUNTPOINT "/dev/$disk_name" 2>/dev/null | grep -E "^/$|^/boot|^/home")
|
||
if [ -n "$mount_check" ]; then
|
||
continue
|
||
fi
|
||
|
||
# Excluir discos ya en uso por el pool principal
|
||
if echo "$pool_devices" | grep -q "^${disk_name}$"; then
|
||
continue
|
||
fi
|
||
|
||
# Verificar estado de uso del dispositivo
|
||
local raid_status=$(check_disk_raid_status "$disk_name")
|
||
local usage_status=""
|
||
|
||
if [ -n "$raid_status" ]; then
|
||
# Dispositivo en uso - agregar a lista de dispositivos en uso
|
||
usage_status="EN_USO"
|
||
in_use_devices+=("$disk_name:$raid_status")
|
||
else
|
||
# Dispositivo disponible
|
||
usage_status="DISPONIBLE"
|
||
fi
|
||
|
||
# Agregar a la lista general y clasificar por tipo
|
||
available_cache_devices+=("$disk_name:$usage_status")
|
||
|
||
if [[ "$disk_name" == nvme* ]]; then
|
||
nvme_devices+=("$disk_name:$usage_status")
|
||
elif lsblk -dpno ROTA "/dev/$disk_name" 2>/dev/null | grep -q "0"; then
|
||
# ROTA=0 significa SSD
|
||
ssd_devices+=("$disk_name:$usage_status")
|
||
else
|
||
other_devices+=("$disk_name:$usage_status")
|
||
fi
|
||
|
||
done < <(lsblk -dpno NAME | grep -v "^/dev/loop")
|
||
|
||
# Mostrar dispositivos disponibles clasificados por tipo
|
||
echo "📀 DISPOSITIVOS PARA CACHE:"
|
||
echo ""
|
||
|
||
if [ ${#nvme_devices[@]} -gt 0 ]; then
|
||
echo "🚀 DISPOSITIVOS NVME (RECOMENDADOS):"
|
||
for device_info in "${nvme_devices[@]}"; do
|
||
local device_name=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
local size=$(lsblk -dpno SIZE "/dev/$device_name" 2>/dev/null | tr -d ' ')
|
||
local model=$(lsblk -dpno MODEL "/dev/$device_name" 2>/dev/null | tr -d ' ')
|
||
|
||
if [ "$usage_status" = "DISPONIBLE" ]; then
|
||
echo " ✅ $device_name - $size - $model"
|
||
else
|
||
echo " ⚠️ $device_name - $size - $model (EN USO: $usage_status - se puede limpiar)"
|
||
fi
|
||
done
|
||
echo ""
|
||
fi
|
||
|
||
if [ ${#ssd_devices[@]} -gt 0 ]; then
|
||
echo "💾 DISPOSITIVOS SSD (ACEPTABLES):"
|
||
for device_info in "${ssd_devices[@]}"; do
|
||
local device_name=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
local size=$(lsblk -dpno SIZE "/dev/$device_name" 2>/dev/null | tr -d ' ')
|
||
local model=$(lsblk -dpno MODEL "/dev/$device_name" 2>/dev/null | tr -d ' ')
|
||
|
||
if [ "$usage_status" = "DISPONIBLE" ]; then
|
||
echo " ⚠️ $device_name - $size - $model"
|
||
else
|
||
echo " ⚠️ $device_name - $size - $model (EN USO: $usage_status - se puede limpiar)"
|
||
fi
|
||
done
|
||
echo ""
|
||
fi
|
||
|
||
if [ ${#other_devices[@]} -gt 0 ]; then
|
||
echo "🐌 OTROS DISPOSITIVOS (NO RECOMENDADOS PARA CACHE):"
|
||
for device_info in "${other_devices[@]}"; do
|
||
local device_name=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
local size=$(lsblk -dpno SIZE "/dev/$device_name" 2>/dev/null | tr -d ' ')
|
||
local model=$(lsblk -dpno MODEL "/dev/$device_name" 2>/dev/null | tr -d ' ')
|
||
|
||
if [ "$usage_status" = "DISPONIBLE" ]; then
|
||
echo " ❌ $device_name - $size - $model"
|
||
else
|
||
echo " ❌ $device_name - $size - $model (EN USO: $usage_status - se puede limpiar)"
|
||
fi
|
||
done
|
||
echo ""
|
||
fi
|
||
|
||
# Mostrar información sobre dispositivos en uso
|
||
if [ ${#in_use_devices[@]} -gt 0 ]; then
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 DEVICES IN USE INFORMATION:"
|
||
else
|
||
echo "💡 INFORMACIÓN SOBRE DISPOSITIVOS EN USO:"
|
||
fi
|
||
echo " • Los dispositivos marcados como 'EN USO' pueden ser limpiados y reutilizados"
|
||
echo " • ⚠️ ADVERTENCIA: Limpiar un dispositivo DESTRUIRÁ todos los datos"
|
||
echo " • Se te pedirá confirmación antes de proceder con dispositivos en uso"
|
||
echo ""
|
||
fi
|
||
|
||
# Verificar dispositivos disponibles y mostrar recomendación apropiada
|
||
if [ ${#nvme_devices[@]} -eq 0 ] && [ ${#ssd_devices[@]} -eq 0 ]; then
|
||
# No hay NVMe ni SSD - advertencia crítica
|
||
echo "⚠️ ADVERTENCIA CRÍTICA:"
|
||
echo " 🔥 NO SE DETECTARON DISPOSITIVOS NVMe O SSD ADECUADOS"
|
||
echo " • Los dispositivos de cache deben ser más rápidos que el almacenamiento principal"
|
||
echo " • Usar dispositivos lentos como cache puede REDUCIR el rendimiento del sistema"
|
||
echo " • Se recomienda FUERTEMENTE conseguir un dispositivo NVMe o SSD para cache"
|
||
echo ""
|
||
|
||
if ! confirm "¿Deseas continuar sin dispositivos rápidos (MUY NO RECOMENDADO)?"; then
|
||
show_message "Configuración de cache cancelada - se recomienda conseguir un dispositivo NVMe o SSD"
|
||
return 0
|
||
fi
|
||
echo ""
|
||
elif [ ${#nvme_devices[@]} -eq 0 ] && [ ${#ssd_devices[@]} -gt 0 ]; then
|
||
# Solo hay SSD, no NVMe - recomendación suave
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 RECOMMENDATION:"
|
||
else
|
||
echo "💡 RECOMENDACIÓN:"
|
||
fi
|
||
echo " ✅ Se detectaron dispositivos SSD (aceptables para cache)"
|
||
echo " 🚀 Para rendimiento óptimo, considera usar NVMe en el futuro"
|
||
echo " 📊 Los SSD son adecuados para la mayoría de casos de uso"
|
||
echo ""
|
||
fi
|
||
|
||
if [ ${#available_cache_devices[@]} -eq 0 ]; then
|
||
show_warning "No se encontraron dispositivos disponibles para cache"
|
||
show_message "Todos los dispositivos están en uso o no son adecuados"
|
||
return 0
|
||
fi
|
||
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "️ CONFIGURATION OPTIONS:"
|
||
else
|
||
echo "️ OPCIONES DE CONFIGURACIÓN:"
|
||
fi
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 1. Configure only L2ARC (read cache)"
|
||
echo " 2. Configure only SLOG (write log)"
|
||
echo " 3. Configure both L2ARC and SLOG"
|
||
echo " 4. Configure partitions on one device (L2ARC + SLOG)"
|
||
echo " 5. Cancel configuration"
|
||
else
|
||
echo " 1. Configurar solo L2ARC (cache de lectura)"
|
||
echo " 2. Configurar solo SLOG (log de escritura)"
|
||
echo " 3. Configurar ambos L2ARC y SLOG"
|
||
echo " 4. Configurar particiones en un dispositivo (L2ARC + SLOG)"
|
||
echo " 5. Cancelar configuración"
|
||
fi
|
||
echo ""
|
||
|
||
while true; do
|
||
read -p "👉 Selecciona una opción (1-5): " config_choice
|
||
case $config_choice in
|
||
1)
|
||
if setup_l2arc_only "$pool_name" "${available_cache_devices[@]}"; then
|
||
break
|
||
else
|
||
echo ""
|
||
echo "️ OPCIONES DE CONFIGURACIÓN:"
|
||
echo " 1. Configurar solo L2ARC (cache de lectura)"
|
||
echo " 2. Configurar solo SLOG (log de escritura)"
|
||
echo " 3. Configurar ambos L2ARC y SLOG"
|
||
echo " 4. Configurar particiones en un dispositivo (L2ARC + SLOG)"
|
||
echo " 5. Cancelar configuración"
|
||
echo ""
|
||
fi
|
||
;;
|
||
2)
|
||
if setup_slog_only "$pool_name" "${available_cache_devices[@]}"; then
|
||
break
|
||
else
|
||
echo ""
|
||
echo "️ OPCIONES DE CONFIGURACIÓN:"
|
||
echo " 1. Configurar solo L2ARC (cache de lectura)"
|
||
echo " 2. Configurar solo SLOG (log de escritura)"
|
||
echo " 3. Configurar ambos L2ARC y SLOG"
|
||
echo " 4. Configurar particiones en un dispositivo (L2ARC + SLOG)"
|
||
echo " 5. Cancelar configuración"
|
||
echo ""
|
||
fi
|
||
;;
|
||
3)
|
||
if setup_l2arc_and_slog_separate "$pool_name" "${available_cache_devices[@]}"; then
|
||
break
|
||
else
|
||
echo ""
|
||
echo "️ OPCIONES DE CONFIGURACIÓN:"
|
||
echo " 1. Configurar solo L2ARC (cache de lectura)"
|
||
echo " 2. Configurar solo SLOG (log de escritura)"
|
||
echo " 3. Configurar ambos L2ARC y SLOG"
|
||
echo " 4. Configurar particiones en un dispositivo (L2ARC + SLOG)"
|
||
echo " 5. Cancelar configuración"
|
||
echo ""
|
||
fi
|
||
;;
|
||
4)
|
||
if setup_partitioned_cache "$pool_name" "${available_cache_devices[@]}"; then
|
||
break
|
||
else
|
||
echo ""
|
||
echo "️ OPCIONES DE CONFIGURACIÓN:"
|
||
echo " 1. Configurar solo L2ARC (cache de lectura)"
|
||
echo " 2. Configurar solo SLOG (log de escritura)"
|
||
echo " 3. Configurar ambos L2ARC y SLOG"
|
||
echo " 4. Configurar particiones en un dispositivo (L2ARC + SLOG)"
|
||
echo " 5. Cancelar configuración"
|
||
echo ""
|
||
fi
|
||
;;
|
||
5)
|
||
show_message "Configuración de cache cancelada"
|
||
return 0
|
||
;;
|
||
*)
|
||
echo "❌ Opción inválida. Selecciona 1, 2, 3, 4 o 5."
|
||
echo ""
|
||
echo "️ OPCIONES DE CONFIGURACIÓN:"
|
||
echo " 1. Configurar solo L2ARC (cache de lectura)"
|
||
echo " 2. Configurar solo SLOG (log de escritura)"
|
||
echo " 3. Configurar ambos L2ARC y SLOG"
|
||
echo " 4. Configurar particiones en un dispositivo (L2ARC + SLOG)"
|
||
echo " 5. Cancelar configuración"
|
||
echo ""
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
# Función para configurar solo L2ARC
|
||
setup_l2arc_only() {
|
||
local pool_name="$1"
|
||
shift
|
||
local available_devices=("$@")
|
||
|
||
show_title "Configuración de L2ARC para '$pool_name'"
|
||
echo ""
|
||
echo "📖 Selecciona el dispositivo para L2ARC (cache de lectura):"
|
||
|
||
for i in "${!available_devices[@]}"; do
|
||
local device_info="${available_devices[$i]}"
|
||
local device_name=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
local size=$(lsblk -dpno SIZE "/dev/$device_name" | tr -d ' ')
|
||
local model=$(lsblk -dpno MODEL "/dev/$device_name" | tr -d ' ')
|
||
|
||
if [ "$usage_status" = "DISPONIBLE" ]; then
|
||
echo " $((i+1)). $device_name - $size - $model"
|
||
else
|
||
echo " $((i+1)). $device_name - $size - $model (EN USO: $usage_status)"
|
||
fi
|
||
done
|
||
|
||
while true; do
|
||
read -p "👉 Selecciona dispositivo (1-${#available_devices[@]}): " device_choice
|
||
if [[ "$device_choice" =~ ^[0-9]+$ ]] && [ "$device_choice" -ge 1 ] && [ "$device_choice" -le ${#available_devices[@]} ]; then
|
||
local device_info="${available_devices[$((device_choice-1))]}"
|
||
local selected_device=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
|
||
# Verificar si el dispositivo está en uso
|
||
if [ "$usage_status" != "DISPONIBLE" ]; then
|
||
echo ""
|
||
echo "⚠️ ADVERTENCIA: El dispositivo $selected_device está EN USO"
|
||
echo " 📁 Uso actual: $usage_status"
|
||
echo " 💀 Limpiar este dispositivo DESTRUIRÁ todos los datos"
|
||
echo ""
|
||
if ! confirm "¿Estás SEGURO de que quieres limpiar y usar $selected_device para L2ARC?"; then
|
||
echo "Selecciona otro dispositivo..."
|
||
continue
|
||
fi
|
||
fi
|
||
|
||
# Verificar si es un disco mecánico
|
||
if ! lsblk -dpno ROTA "/dev/$selected_device" 2>/dev/null | grep -q "0"; then
|
||
echo ""
|
||
echo "🚨 ADVERTENCIA: El dispositivo $selected_device parece ser un DISCO MECÁNICO"
|
||
echo " ❌ Los discos mecánicos NO deben usarse como cache"
|
||
echo " 📉 Esto EMPEORARÁ significativamente el rendimiento del sistema"
|
||
echo " ✅ Usa solo SSD o NVMe para cache"
|
||
echo ""
|
||
if ! confirm "¿Estás SEGURO de que quieres usar este disco mecánico? (MUY NO RECOMENDADO)"; then
|
||
echo "Selecciona otro dispositivo..."
|
||
continue
|
||
fi
|
||
echo ""
|
||
if ! confirm "⚠️ ÚLTIMA ADVERTENCIA: ¿Realmente quieres proceder con un disco mecánico?"; then
|
||
echo "Selecciona otro dispositivo..."
|
||
continue
|
||
fi
|
||
fi
|
||
break
|
||
else
|
||
echo "❌ Selección inválida. Usa números del 1 al ${#available_devices[@]}."
|
||
fi
|
||
done
|
||
|
||
# Confirmar y aplicar
|
||
echo ""
|
||
show_warning "⚠️ Esto limpiará completamente el dispositivo /dev/$selected_device"
|
||
if confirm "¿Continuar con la configuración de L2ARC en /dev/$selected_device?"; then
|
||
show_message "Preparando dispositivo /dev/$selected_device para L2ARC..."
|
||
|
||
# Limpiar dispositivo
|
||
clean_disk "$selected_device"
|
||
|
||
# Agregar como L2ARC
|
||
show_message "Agregando /dev/$selected_device como L2ARC al pool '$pool_name'..."
|
||
if sudo zpool add "$pool_name" cache "/dev/$selected_device"; then
|
||
show_message "✅ L2ARC configurado exitosamente"
|
||
echo ""
|
||
show_message "📊 CONFIGURACIÓN L2ARC COMPLETADA:"
|
||
echo " Pool: $pool_name"
|
||
echo " Dispositivo L2ARC: /dev/$selected_device"
|
||
echo " Función: Cache de lectura (mejora acceso a datos frecuentes)"
|
||
echo " 💡 Cache devices no requieren compatibilidad de ashift"
|
||
return 0
|
||
else
|
||
show_error "❌ Error configurando L2ARC"
|
||
return 1
|
||
fi
|
||
else
|
||
show_message "Configuración de L2ARC cancelada"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# Función para configurar solo SLOG
|
||
setup_slog_only() {
|
||
local pool_name="$1"
|
||
shift
|
||
local available_devices=("$@")
|
||
|
||
show_title "Configuración de SLOG para '$pool_name'"
|
||
echo ""
|
||
echo "⚠️ IMPORTANTE - REQUISITOS PARA SLOG:"
|
||
echo " • Usar SSD de alta calidad con protección contra cortes de energía"
|
||
echo " • Evitar dispositivos USB o SD para SLOG"
|
||
echo " • Preferir NVMe > SATA SSD > otros"
|
||
echo ""
|
||
echo "📖 Selecciona el dispositivo para SLOG (log de escritura):"
|
||
|
||
for i in "${!available_devices[@]}"; do
|
||
local device_info="${available_devices[$i]}"
|
||
local device_name=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
local size=$(lsblk -dpno SIZE "/dev/$device_name" | tr -d ' ')
|
||
local model=$(lsblk -dpno MODEL "/dev/$device_name" | tr -d ' ')
|
||
local recommendation=""
|
||
|
||
if [[ "$device_name" == nvme* ]]; then
|
||
recommendation=" ⭐ RECOMENDADO"
|
||
elif lsblk -dpno ROTA "/dev/$device_name" | grep -q "0"; then
|
||
recommendation=" ✅ ADECUADO"
|
||
else
|
||
recommendation=" ⚠️ NO RECOMENDADO (HDD)"
|
||
fi
|
||
|
||
if [ "$usage_status" = "DISPONIBLE" ]; then
|
||
echo " $((i+1)). $device_name - $size - $model$recommendation"
|
||
else
|
||
echo " $((i+1)). $device_name - $size - $model$recommendation (EN USO: $usage_status)"
|
||
fi
|
||
done
|
||
|
||
while true; do
|
||
read -p "👉 Selecciona dispositivo (1-${#available_devices[@]}): " device_choice
|
||
if [[ "$device_choice" =~ ^[0-9]+$ ]] && [ "$device_choice" -ge 1 ] && [ "$device_choice" -le ${#available_devices[@]} ]; then
|
||
local device_info="${available_devices[$((device_choice-1))]}"
|
||
local selected_device=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
|
||
# Verificar si el dispositivo está en uso
|
||
if [ "$usage_status" != "DISPONIBLE" ]; then
|
||
echo ""
|
||
echo "⚠️ ADVERTENCIA CRÍTICA: El dispositivo $selected_device está EN USO"
|
||
echo " 📁 Uso actual: $usage_status"
|
||
echo " 💀 Limpiar este dispositivo DESTRUIRÁ todos los datos"
|
||
echo " 🔧 SLOG es crítico - asegúrate de que puedes perder estos datos"
|
||
echo ""
|
||
if ! confirm "¿Estás SEGURO de que quieres limpiar y usar $selected_device para SLOG?"; then
|
||
echo "Selecciona otro dispositivo..."
|
||
continue
|
||
fi
|
||
fi
|
||
break
|
||
else
|
||
echo "❌ Selección inválida. Usa números del 1 al ${#available_devices[@]}."
|
||
fi
|
||
done
|
||
|
||
# Verificar si es adecuado para SLOG
|
||
if ! [[ "$selected_device" == nvme* ]] && lsblk -dpno ROTA "/dev/$selected_device" | grep -q "1"; then
|
||
echo ""
|
||
echo "🚨 ADVERTENCIA CRÍTICA: El dispositivo $selected_device es un DISCO MECÁNICO"
|
||
echo " ❌ Los discos mecánicos NO deben usarse como SLOG"
|
||
echo " 💀 Esto puede causar PÉRDIDA DE DATOS y rendimiento EXTREMADAMENTE pobre"
|
||
echo " 🔧 SLOG requiere dispositivos de baja latencia (SSD/NVMe)"
|
||
echo " ⚡ Un SLOG lento puede bloquear TODAS las escrituras del sistema"
|
||
echo ""
|
||
if ! confirm "¿Estás SEGURO de que quieres usar este disco mecánico para SLOG? (PELIGROSO)"; then
|
||
show_message "Configuración cancelada por el usuario"
|
||
return 0
|
||
fi
|
||
echo ""
|
||
if ! confirm "⚠️ ÚLTIMA ADVERTENCIA: ¿Realmente quieres proceder? (PUEDE CAUSAR PROBLEMAS GRAVES)"; then
|
||
show_message "Configuración cancelada por el usuario"
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
# Confirmar y aplicar
|
||
echo ""
|
||
show_warning "⚠️ Esto limpiará completamente el dispositivo /dev/$selected_device"
|
||
if confirm "¿Continuar con la configuración de SLOG en /dev/$selected_device?"; then
|
||
show_message "Preparando dispositivo /dev/$selected_device para SLOG..."
|
||
|
||
# Limpiar dispositivo
|
||
clean_disk "$selected_device"
|
||
|
||
# Agregar como SLOG
|
||
show_message "Agregando /dev/$selected_device como SLOG al pool '$pool_name'..."
|
||
if sudo zpool add "$pool_name" log "/dev/$selected_device"; then
|
||
show_message "✅ SLOG configurado exitosamente"
|
||
echo ""
|
||
show_message "📊 CONFIGURACIÓN SLOG COMPLETADA:"
|
||
echo " Pool: $pool_name"
|
||
echo " Dispositivo SLOG: /dev/$selected_device"
|
||
echo " Función: Log de escritura (mejora escrituras síncronas)"
|
||
echo " 💡 Cache devices no requieren compatibilidad de ashift"
|
||
return 0
|
||
else
|
||
show_error "❌ Error configurando SLOG"
|
||
return 1
|
||
fi
|
||
else
|
||
show_message "Configuración de SLOG cancelada"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# Función para configurar L2ARC y SLOG en dispositivos separados
|
||
setup_l2arc_and_slog_separate() {
|
||
local pool_name="$1"
|
||
shift
|
||
local available_devices=("$@")
|
||
|
||
if [ ${#available_devices[@]} -lt 2 ]; then
|
||
show_error "Se necesitan al menos 2 dispositivos disponibles para configurar L2ARC y SLOG por separado"
|
||
return 1
|
||
fi
|
||
|
||
show_title "Configuración de L2ARC y SLOG Separados para '$pool_name'"
|
||
echo ""
|
||
echo "📖 Selecciona dispositivos para L2ARC y SLOG:"
|
||
echo ""
|
||
|
||
# Mostrar dispositivos con recomendaciones
|
||
for i in "${!available_devices[@]}"; do
|
||
local device_info="${available_devices[$i]}"
|
||
local device_name=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
local size=$(lsblk -dpno SIZE "/dev/$device_name" | tr -d ' ')
|
||
local model=$(lsblk -dpno MODEL "/dev/$device_name" | tr -d ' ')
|
||
local recommendation=""
|
||
|
||
if [[ "$device_name" == nvme* ]]; then
|
||
recommendation=" ⭐ EXCELENTE para SLOG, BUENO para L2ARC"
|
||
elif lsblk -dpno ROTA "/dev/$device_name" | grep -q "0"; then
|
||
recommendation=" ✅ BUENO para L2ARC, REGULAR para SLOG"
|
||
else
|
||
recommendation=" ⚠️ SOLO para L2ARC (NO para SLOG)"
|
||
fi
|
||
|
||
if [ "$usage_status" = "DISPONIBLE" ]; then
|
||
echo " $((i+1)). $device_name - $size - $model$recommendation"
|
||
else
|
||
echo " $((i+1)). $device_name - $size - $model$recommendation (EN USO: $usage_status)"
|
||
fi
|
||
done
|
||
|
||
# Seleccionar dispositivo para L2ARC
|
||
echo ""
|
||
echo "🚀 SELECCIÓN DE L2ARC:"
|
||
while true; do
|
||
read -p "👉 Dispositivo para L2ARC (1-${#available_devices[@]}): " l2arc_choice
|
||
if [[ "$l2arc_choice" =~ ^[0-9]+$ ]] && [ "$l2arc_choice" -ge 1 ] && [ "$l2arc_choice" -le ${#available_devices[@]} ]; then
|
||
local device_info="${available_devices[$((l2arc_choice-1))]}"
|
||
local l2arc_device=$(echo "$device_info" | cut -d: -f1)
|
||
local l2arc_usage=$(echo "$device_info" | cut -d: -f2)
|
||
|
||
# Verificar si el dispositivo L2ARC está en uso
|
||
if [ "$l2arc_usage" != "DISPONIBLE" ]; then
|
||
echo ""
|
||
echo "⚠️ ADVERTENCIA: El dispositivo $l2arc_device está EN USO"
|
||
echo " 📁 Uso actual: $l2arc_usage"
|
||
echo " 💀 Limpiar este dispositivo DESTRUIRÁ todos los datos"
|
||
echo ""
|
||
if ! confirm "¿Continuar con $l2arc_device para L2ARC?"; then
|
||
echo "Selecciona otro dispositivo..."
|
||
continue
|
||
fi
|
||
fi
|
||
break
|
||
else
|
||
echo "❌ Selección inválida. Usa números del 1 al ${#available_devices[@]}."
|
||
fi
|
||
done
|
||
|
||
# Seleccionar dispositivo para SLOG (excluyendo el ya seleccionado)
|
||
echo ""
|
||
echo "📝 SELECCIÓN DE SLOG:"
|
||
echo "Dispositivos disponibles (excluyendo $l2arc_device):"
|
||
local slog_devices=()
|
||
for i in "${!available_devices[@]}"; do
|
||
local device_info="${available_devices[$i]}"
|
||
local device_name=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
|
||
if [ "$device_name" != "$l2arc_device" ]; then
|
||
slog_devices+=("$device_info")
|
||
local size=$(lsblk -dpno SIZE "/dev/$device_name" | tr -d ' ')
|
||
local model=$(lsblk -dpno MODEL "/dev/$device_name" | tr -d ' ')
|
||
local recommendation=""
|
||
|
||
if [[ "$device_name" == nvme* ]]; then
|
||
recommendation=" ⭐ RECOMENDADO"
|
||
elif lsblk -dpno ROTA "/dev/$device_name" | grep -q "0"; then
|
||
recommendation=" ✅ ADECUADO"
|
||
else
|
||
recommendation=" ⚠️ NO RECOMENDADO"
|
||
fi
|
||
|
||
if [ "$usage_status" = "DISPONIBLE" ]; then
|
||
echo " ${#slog_devices[@]}. $device_name - $size - $model$recommendation"
|
||
else
|
||
echo " ${#slog_devices[@]}. $device_name - $size - $model$recommendation (EN USO: $usage_status)"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
while true; do
|
||
read -p "👉 Dispositivo para SLOG (1-${#slog_devices[@]}): " slog_choice
|
||
if [[ "$slog_choice" =~ ^[0-9]+$ ]] && [ "$slog_choice" -ge 1 ] && [ "$slog_choice" -le ${#slog_devices[@]} ]; then
|
||
local device_info="${slog_devices[$((slog_choice-1))]}"
|
||
local slog_device=$(echo "$device_info" | cut -d: -f1)
|
||
local slog_usage=$(echo "$device_info" | cut -d: -f2)
|
||
|
||
# Verificar si el dispositivo SLOG está en uso
|
||
if [ "$slog_usage" != "DISPONIBLE" ]; then
|
||
echo ""
|
||
echo "⚠️ ADVERTENCIA CRÍTICA: El dispositivo $slog_device está EN USO"
|
||
echo " 📁 Uso actual: $slog_usage"
|
||
echo " 💀 Limpiar este dispositivo DESTRUIRÁ todos los datos"
|
||
echo " 🔧 SLOG es crítico para integridad de datos"
|
||
echo ""
|
||
if ! confirm "¿Continuar con $slog_device para SLOG?"; then
|
||
echo "Selecciona otro dispositivo..."
|
||
continue
|
||
fi
|
||
fi
|
||
break
|
||
else
|
||
echo "❌ Selección inválida. Usa números del 1 al ${#slog_devices[@]}."
|
||
fi
|
||
done
|
||
|
||
# Verificar SLOG si es HDD
|
||
if ! [[ "$slog_device" == nvme* ]] && lsblk -dpno ROTA "/dev/$slog_device" | grep -q "1"; then
|
||
show_warning "⚠️ ADVERTENCIA: Dispositivo SLOG seleccionado es HDD"
|
||
if ! confirm "¿Continuar con HDD para SLOG? (no recomendado)"; then
|
||
show_message "Configuración cancelada"
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
# Mostrar resumen y confirmar
|
||
echo ""
|
||
show_message "📊 RESUMEN DE CONFIGURACIÓN:"
|
||
echo " Pool: $pool_name"
|
||
echo " L2ARC: /dev/$l2arc_device (cache de lectura)"
|
||
echo " SLOG: /dev/$slog_device (log de escritura)"
|
||
echo ""
|
||
|
||
show_warning "⚠️ Esto limpiará completamente ambos dispositivos"
|
||
if confirm "¿Continuar con la configuración?"; then
|
||
# Configurar L2ARC
|
||
show_message "Preparando /dev/$l2arc_device para L2ARC..."
|
||
clean_disk "$l2arc_device"
|
||
|
||
# Verificar compatibilidad de tamaño de sector para L2ARC
|
||
show_message "Verificando compatibilidad de sector para L2ARC..."
|
||
local pool_sector_size=$(zpool get ashift "$pool_name" -H -o value 2>/dev/null | head -n 1)
|
||
local l2arc_sector_size=$(sudo blockdev --getpbsz "/dev/$l2arc_device" 2>/dev/null)
|
||
local l2arc_force=""
|
||
|
||
if [ -n "$pool_sector_size" ] && [ -n "$l2arc_sector_size" ]; then
|
||
local pool_bytes=$((2 ** pool_sector_size))
|
||
if [ "$l2arc_sector_size" -ne "$pool_bytes" ]; then
|
||
echo " ⚠️ Pool: ${pool_bytes} bytes | L2ARC: ${l2arc_sector_size} bytes"
|
||
if confirm "¿Forzar L2ARC?"; then
|
||
l2arc_force="-f"
|
||
else
|
||
show_message "Configuración cancelada"
|
||
return 1
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
show_message "Agregando L2ARC al pool..."
|
||
if ! sudo zpool add $l2arc_force "$pool_name" cache "/dev/$l2arc_device"; then
|
||
show_error "❌ Error configurando L2ARC"
|
||
return 1
|
||
fi
|
||
|
||
# Configurar SLOG
|
||
show_message "Preparando /dev/$slog_device para SLOG..."
|
||
clean_disk "$slog_device"
|
||
|
||
# Verificar compatibilidad de tamaño de sector para SLOG
|
||
show_message "Verificando compatibilidad de sector para SLOG..."
|
||
local slog_sector_size=$(sudo blockdev --getpbsz "/dev/$slog_device" 2>/dev/null)
|
||
local slog_force=""
|
||
|
||
if [ -n "$pool_sector_size" ] && [ -n "$slog_sector_size" ]; then
|
||
local pool_bytes=$((2 ** pool_sector_size))
|
||
if [ "$slog_sector_size" -ne "$pool_bytes" ]; then
|
||
echo " ⚠️ Pool: ${pool_bytes} bytes | SLOG: ${slog_sector_size} bytes"
|
||
if confirm "¿Forzar SLOG? (RIESGOSO para integridad)"; then
|
||
slog_force="-f"
|
||
else
|
||
show_message "Configuración cancelada"
|
||
return 1
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
show_message "Agregando SLOG al pool..."
|
||
if ! sudo zpool add $slog_force "$pool_name" log "/dev/$slog_device"; then
|
||
show_error "❌ Error configurando SLOG"
|
||
return 1
|
||
fi
|
||
|
||
show_message "✅ L2ARC y SLOG configurados exitosamente"
|
||
echo ""
|
||
show_message "📊 CONFIGURACIÓN COMPLETADA:"
|
||
echo " Pool: $pool_name"
|
||
echo " L2ARC: /dev/$l2arc_device (mejora lecturas frecuentes)"
|
||
echo " SLOG: /dev/$slog_device (mejora escrituras síncronas)"
|
||
return 0
|
||
else
|
||
show_message "Configuración cancelada"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# Función para configurar particiones L2ARC + SLOG en un dispositivo
|
||
setup_partitioned_cache() {
|
||
local pool_name="$1"
|
||
shift
|
||
local available_devices=("$@")
|
||
|
||
show_title "Configuración de L2ARC + SLOG Particionado para '$pool_name'"
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 PARTITION CONFIGURATION:"
|
||
else
|
||
echo "💡 CONFIGURACIÓN PARTICIONADA:"
|
||
fi
|
||
echo " Esta opción crea particiones en un solo dispositivo:"
|
||
echo " • 80% del espacio para L2ARC (cache de lectura)"
|
||
echo " • 20% del espacio para SLOG (log de escritura)"
|
||
echo ""
|
||
echo "⚠️ RECOMENDACIONES:"
|
||
echo " • Usar solo con SSD de alta calidad (preferiblemente NVMe)"
|
||
echo " • El dispositivo debe tener al menos 8GB de espacio"
|
||
echo " • No recomendado para HDD o dispositivos USB"
|
||
echo ""
|
||
|
||
# Mostrar dispositivos recomendados
|
||
echo "💾 DISPOSITIVOS DISPONIBLES:"
|
||
for i in "${!available_devices[@]}"; do
|
||
local device_info="${available_devices[$i]}"
|
||
local device_name=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
local size=$(lsblk -dpno SIZE "/dev/$device_name" | tr -d ' ')
|
||
local size_bytes=$(lsblk -dpno SIZE "/dev/$device_name" --bytes)
|
||
local model=$(lsblk -dpno MODEL "/dev/$device_name" | tr -d ' ')
|
||
local recommendation=""
|
||
|
||
if [[ "$device_name" == nvme* ]]; then
|
||
recommendation=" ⭐ EXCELENTE"
|
||
elif lsblk -dpno ROTA "/dev/$device_name" | grep -q "0"; then
|
||
if [ "$size_bytes" -gt 8589934592 ]; then # 8GB
|
||
recommendation=" ✅ ADECUADO"
|
||
else
|
||
recommendation=" ⚠️ PEQUEÑO (mín 8GB recomendado)"
|
||
fi
|
||
else
|
||
recommendation=" ❌ NO RECOMENDADO (HDD)"
|
||
fi
|
||
|
||
if [ "$usage_status" = "DISPONIBLE" ]; then
|
||
echo " $((i+1)). $device_name - $size - $model$recommendation"
|
||
else
|
||
echo " $((i+1)). $device_name - $size - $model$recommendation (EN USO: $usage_status)"
|
||
fi
|
||
done
|
||
|
||
while true; do
|
||
read -p "👉 Selecciona dispositivo (1-${#available_devices[@]}): " device_choice
|
||
if [[ "$device_choice" =~ ^[0-9]+$ ]] && [ "$device_choice" -ge 1 ] && [ "$device_choice" -le ${#available_devices[@]} ]; then
|
||
local device_info="${available_devices[$((device_choice-1))]}"
|
||
local selected_device=$(echo "$device_info" | cut -d: -f1)
|
||
local usage_status=$(echo "$device_info" | cut -d: -f2)
|
||
|
||
# Verificar si el dispositivo está en uso
|
||
if [ "$usage_status" != "DISPONIBLE" ]; then
|
||
echo ""
|
||
echo "⚠️ ADVERTENCIA: El dispositivo $selected_device está EN USO"
|
||
echo " 📁 Uso actual: $usage_status"
|
||
echo " 💀 Crear particiones DESTRUIRÁ todos los datos"
|
||
echo ""
|
||
if ! confirm "¿Estás SEGURO de que quieres limpiar y particionar $selected_device?"; then
|
||
echo "Selecciona otro dispositivo..."
|
||
continue
|
||
fi
|
||
fi
|
||
break
|
||
else
|
||
echo "❌ Selección inválida. Usa números del 1 al ${#available_devices[@]}."
|
||
fi
|
||
done
|
||
|
||
# Verificar si el dispositivo es adecuado
|
||
local size_bytes=$(lsblk -dpno SIZE "/dev/$selected_device" --bytes)
|
||
if [ "$size_bytes" -lt 8589934592 ]; then # 8GB
|
||
show_warning "⚠️ El dispositivo es menor a 8GB, puede no ser óptimo"
|
||
if ! confirm "¿Continuar de todas formas?"; then
|
||
show_message "Configuración cancelada"
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
if ! [[ "$selected_device" == nvme* ]] && lsblk -dpno ROTA "/dev/$selected_device" | grep -q "1"; then
|
||
show_warning "⚠️ ADVERTENCIA: El dispositivo seleccionado es un HDD"
|
||
show_warning " No es recomendado usar HDD para particionado L2ARC+SLOG"
|
||
if ! confirm "¿Estás seguro de continuar?"; then
|
||
show_message "Configuración cancelada"
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
# Mostrar resumen
|
||
local size_gb=$(( size_bytes / 1024 / 1024 / 1024 ))
|
||
local l2arc_size=$(( size_gb * 80 / 100 ))
|
||
local slog_size=$(( size_gb * 20 / 100 ))
|
||
|
||
echo ""
|
||
show_message "📊 CONFIGURACIÓN PLANIFICADA:"
|
||
echo " Dispositivo: /dev/$selected_device ($size_gb GB)"
|
||
echo " Partición L2ARC: ~${l2arc_size}GB (80%)"
|
||
echo " Partición SLOG: ~${slog_size}GB (20%)"
|
||
echo ""
|
||
|
||
show_warning "⚠️ Esto destruirá todos los datos en /dev/$selected_device"
|
||
if confirm "¿Continuar con el particionado?"; then
|
||
echo ""
|
||
show_message "🔍 VERIFICACIÓN PREVIA DEL POOL:"
|
||
echo " Pool: $pool_name"
|
||
echo " Estado: $(zpool get health "$pool_name" -H -o value 2>/dev/null || echo "DESCONOCIDO")"
|
||
echo " Versión: $(zpool get version "$pool_name" -H -o value 2>/dev/null || echo "DESCONOCIDA")"
|
||
echo ""
|
||
|
||
show_message "Preparando dispositivo /dev/$selected_device..."
|
||
|
||
# Limpiar dispositivo
|
||
if ! clean_disk "$selected_device"; then
|
||
show_error "❌ Error limpiando el dispositivo"
|
||
show_message "Regresando al menú anterior..."
|
||
return 1
|
||
fi
|
||
|
||
# Crear tabla de particiones GPT
|
||
show_message "Creando tabla de particiones..."
|
||
if ! sudo parted "/dev/$selected_device" --script mklabel gpt; then
|
||
show_error "❌ Error creando tabla de particiones"
|
||
show_message "Regresando al menú anterior..."
|
||
return 1
|
||
fi
|
||
|
||
# Crear partición L2ARC (80%)
|
||
show_message "Creando partición L2ARC (80% del espacio)..."
|
||
if ! sudo parted "/dev/$selected_device" --script mkpart l2arc ext4 1MiB 80%; then
|
||
show_error "❌ Error creando partición L2ARC"
|
||
show_message "Regresando al menú anterior..."
|
||
return 1
|
||
fi
|
||
|
||
# Crear partición SLOG (20%)
|
||
show_message "Creando partición SLOG (20% del espacio)..."
|
||
if ! sudo parted "/dev/$selected_device" --script mkpart slog ext4 80% 100%; then
|
||
show_error "❌ Error creando partición SLOG"
|
||
show_message "Regresando al menú anterior..."
|
||
return 1
|
||
fi
|
||
|
||
# Esperar que el kernel reconozca las particiones
|
||
sudo partprobe "/dev/$selected_device"
|
||
sleep 3
|
||
|
||
# Determinar nombres de particiones
|
||
local l2arc_partition="${selected_device}1"
|
||
local slog_partition="${selected_device}2"
|
||
|
||
# Si es NVMe, las particiones tienen formato diferente
|
||
if [[ "$selected_device" == nvme* ]]; then
|
||
l2arc_partition="${selected_device}p1"
|
||
slog_partition="${selected_device}p2"
|
||
fi
|
||
|
||
# Verificar que las particiones existen
|
||
if [ ! -b "/dev/$l2arc_partition" ] || [ ! -b "/dev/$slog_partition" ]; then
|
||
show_error "❌ Error: Las particiones no se crearon correctamente"
|
||
show_message "Regresando al menú anterior..."
|
||
return 1
|
||
fi
|
||
|
||
# Agregar L2ARC y SLOG
|
||
echo ""
|
||
show_message "🔧 Agregando L2ARC y SLOG al pool en un solo comando..."
|
||
echo " 💡 Cache devices no requieren compatibilidad de ashift"
|
||
echo " Comando: zpool add '$pool_name' cache '/dev/$l2arc_partition' log '/dev/$slog_partition'"
|
||
|
||
# Verificar que ambas particiones existen y son accesibles
|
||
if [ ! -b "/dev/$l2arc_partition" ]; then
|
||
show_error "❌ Partición L2ARC /dev/$l2arc_partition no existe"
|
||
return 1
|
||
fi
|
||
|
||
if [ -n "$pool_sector_size" ] && [ -n "$cache_sector_size" ]; then
|
||
local pool_bytes=$((2 ** pool_sector_size))
|
||
echo " Pool sector size: ${pool_bytes} bytes (ashift=$pool_sector_size)"
|
||
echo " Cache sector size: ${cache_sector_size} bytes"
|
||
|
||
if [ "$cache_sector_size" -ne "$pool_bytes" ]; then
|
||
echo ""
|
||
show_error "⚠️ INCOMPATIBILIDAD DE TAMAÑO DE SECTOR:"
|
||
echo " 📊 Pool '$pool_name': ${pool_bytes} bytes"
|
||
echo " 💾 Cache device: ${cache_sector_size} bytes"
|
||
echo ""
|
||
show_message "[INFO] 🔍 CAUSA DEL PROBLEMA:"
|
||
echo " El pool fue creado con ashift=$pool_sector_size"
|
||
if [ "$pool_sector_size" -eq 0 ]; then
|
||
echo " ⚠️ ashift=0 indica pool creado sin configuración óptima"
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo " 💡 For new pools, the script now uses automatic ashift"
|
||
else
|
||
echo " 💡 Para nuevos pools, el script ahora usa ashift automático"
|
||
fi
|
||
echo " � Recomendación: Recrear pool con ashift=12 para compatibilidad"
|
||
fi
|
||
echo ""
|
||
echo "�💡 OPCIONES DISPONIBLES:"
|
||
echo " 1. Continuar SIN cache (recomendado)"
|
||
echo " 2. Forzar adición con -f (puede causar problemas)"
|
||
echo " 3. Usar un dispositivo con sector compatible"
|
||
echo " 4. Recrear pool con ashift correcto (óptimo a largo plazo)"
|
||
echo ""
|
||
|
||
read -p "👉 Selecciona opción (1-3): " sector_choice
|
||
case $sector_choice in
|
||
1)
|
||
show_message "Configuración cancelada - pool funcionará sin cache"
|
||
return 1
|
||
;;
|
||
2)
|
||
show_warning "⚠️ Usando -f para forzar la adición..."
|
||
local force_flag="-f"
|
||
;;
|
||
3)
|
||
show_message "Configuración cancelada - selecciona otro dispositivo"
|
||
return 1
|
||
;;
|
||
*)
|
||
show_message "Opción inválida - cancelando configuración"
|
||
return 1
|
||
;;
|
||
esac
|
||
else
|
||
echo " ✅ Tamaños de sector compatibles"
|
||
local force_flag=""
|
||
fi
|
||
else
|
||
echo " ⚠️ No se pudo verificar tamaño de sector completamente"
|
||
echo " Intentando adición normal..."
|
||
local force_flag=""
|
||
fi
|
||
|
||
# Agregar L2ARC
|
||
echo ""
|
||
show_message "🔧 Agregando L2ARC y SLOG al pool en un solo comando..."
|
||
echo " Comando: zpool add $force_flag '$pool_name' cache '/dev/$l2arc_partition' log '/dev/$slog_partition'"
|
||
|
||
# Verificar que ambas particiones existen y son accesibles
|
||
if [ ! -b "/dev/$l2arc_partition" ]; then
|
||
show_error "❌ Partición L2ARC /dev/$l2arc_partition no existe"
|
||
return 1
|
||
fi
|
||
|
||
if [ ! -b "/dev/$slog_partition" ]; then
|
||
show_error "❌ Partición SLOG /dev/$slog_partition no existe"
|
||
return 1
|
||
fi
|
||
|
||
# Mostrar información de ambas particiones antes de agregar
|
||
echo " Partición L2ARC: $(lsblk -no SIZE,FSTYPE "/dev/$l2arc_partition" 2>/dev/null || echo "sin formato")"
|
||
echo " Partición SLOG: $(lsblk -no SIZE,FSTYPE "/dev/$slog_partition" 2>/dev/null || echo "sin formato")"
|
||
|
||
if sudo zpool add "$pool_name" cache "/dev/$l2arc_partition" log "/dev/$slog_partition" 2>&1; then
|
||
show_message "✅ L2ARC y SLOG agregados exitosamente en un solo comando"
|
||
echo ""
|
||
show_message "📊 CONFIGURACIÓN COMPLETADA:"
|
||
echo " Pool: $pool_name"
|
||
echo " Dispositivo base: /dev/$selected_device"
|
||
echo " L2ARC: /dev/$l2arc_partition (~${l2arc_size}GB)"
|
||
echo " SLOG: /dev/$slog_partition (~${slog_size}GB)"
|
||
echo " Función: Cache de lectura + Log de escritura optimizados"
|
||
echo " 💡 Ambos dispositivos agregados en comando único"
|
||
return 0
|
||
else
|
||
local exit_code=$?
|
||
show_error "❌ Error agregando L2ARC y SLOG (código: $exit_code)"
|
||
echo ""
|
||
echo "� INFORMACIÓN DE DIAGNÓSTICO:"
|
||
echo " • Pool status:"
|
||
zpool status "$pool_name" | head -n 10
|
||
echo " • Dispositivo L2ARC:"
|
||
lsblk "/dev/$l2arc_partition" 2>/dev/null || echo " No se puede leer la partición"
|
||
echo " • Dispositivo SLOG:"
|
||
lsblk "/dev/$slog_partition" 2>/dev/null || echo " No se puede leer la partición"
|
||
echo " • Posibles causas:"
|
||
echo " - Partición ya en uso"
|
||
echo " - Permisos insuficientes"
|
||
echo " - Pool en estado degradado"
|
||
echo " 💡 Cache devices no requieren compatibilidad de ashift"
|
||
show_message "Regresando al menú anterior..."
|
||
return 1
|
||
fi
|
||
else
|
||
show_message "Configuración cancelada"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# Función para crear snapshots iniciales
|
||
create_initial_snapshots() {
|
||
|
||
if sudo zpool add $force_flag "$pool_name" log "/dev/$slog_partition" 2>&1; then
|
||
show_message "✅ SLOG agregado exitosamente"
|
||
else
|
||
local exit_code=$?
|
||
show_error "❌ Error agregando SLOG (código: $exit_code)"
|
||
echo ""
|
||
echo "� INFORMACIÓN DE DIAGNÓSTICO:"
|
||
echo " • Pool status:"
|
||
zpool status "$pool_name" | head -n 10
|
||
echo " • Dispositivo SLOG:"
|
||
lsblk "/dev/$slog_partition" 2>/dev/null || echo " No se puede leer la partición"
|
||
echo " • Posibles causas:"
|
||
echo " - Sector size incompatible"
|
||
echo " - Partición ya en uso"
|
||
echo " - Permisos insuficientes"
|
||
echo " - Pool en estado degradado"
|
||
show_message "Regresando al menú anterior..."
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# Función para crear snapshots iniciales
|
||
create_initial_snapshots() {
|
||
local pool_name="$1"
|
||
|
||
show_title "Creación de Snapshots Iniciales"
|
||
echo ""
|
||
if [ "$SCRIPT_LANGUAGE" = "en" ]; then
|
||
echo "💡 Snapshots are instant copies of datasets that take no initial space."
|
||
else
|
||
echo "💡 Los snapshots son copias instantáneas de datasets que no ocupan espacio inicial."
|
||
fi
|
||
echo " Son útiles para:"
|
||
echo " • Backups rápidos antes de cambios importantes"
|
||
echo " • Restauración rápida a estados anteriores"
|
||
echo " • Bases para replicación de datos"
|
||
echo ""
|
||
|
||
# Obtener datasets del pool
|
||
local datasets=$(zfs list -H -o name -r "$pool_name" 2>/dev/null)
|
||
|
||
if [ -n "$datasets" ]; then
|
||
echo "📁 Datasets disponibles para snapshot:"
|
||
for dataset in $datasets; do
|
||
echo " • $dataset"
|
||
done
|
||
echo ""
|
||
|
||
if confirm "¿Crear snapshot inicial de todos los datasets?"; then
|
||
local timestamp=$(date +"%Y%m%d-%H%M%S")
|
||
local snapshot_name="inicial-$timestamp"
|
||
|
||
for dataset in $datasets; do
|
||
show_message "Creando snapshot: $dataset@$snapshot_name"
|
||
if sudo zfs snapshot "$dataset@$snapshot_name"; then
|
||
show_message "✅ Snapshot creado: $dataset@$snapshot_name"
|
||
else
|
||
show_error "❌ Error creando snapshot de $dataset"
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
show_message "📊 Snapshots creados:"
|
||
sudo zfs list -t snapshot -o name,used,creation | grep "@$snapshot_name"
|
||
fi
|
||
else
|
||
show_warning "No se encontraron datasets en el pool '$pool_name'"
|
||
fi
|
||
}
|
||
|
||
# Función para mostrar estado completo del pool
|
||
show_pool_status() {
|
||
local pool_name="$1"
|
||
|
||
# Debugging para identificar el problema
|
||
if [ -z "$pool_name" ]; then
|
||
show_error "Error crítico: show_pool_status llamado sin parámetro de pool_name"
|
||
echo "Información de debug:"
|
||
echo " Parámetros recibidos: '$@'"
|
||
echo " Número de parámetros: $#"
|
||
echo " Variable global POOL_NAME: '$POOL_NAME'"
|
||
echo " Pools disponibles: $(zpool list -H -o name 2>/dev/null | tr '\n' ' ')"
|
||
read -p "Presiona Enter para continuar..."
|
||
return 1
|
||
fi
|
||
|
||
show_title "Estado Completo del Pool '$pool_name'"
|
||
echo ""
|
||
|
||
# Estado del pool
|
||
echo "🏊 ESTADO DEL POOL:"
|
||
sudo zpool status "$pool_name"
|
||
echo ""
|
||
|
||
# Información del pool
|
||
echo "📊 INFORMACIÓN DEL POOL:"
|
||
sudo zpool list "$pool_name"
|
||
echo ""
|
||
|
||
# Datasets
|
||
echo "📁 DATASETS:"
|
||
sudo zfs list -r "$pool_name"
|
||
echo ""
|
||
|
||
# Snapshots (si existen)
|
||
local snapshots=$(zfs list -t snapshot -H -o name 2>/dev/null | grep "^$pool_name")
|
||
if [ -n "$snapshots" ]; then
|
||
echo "📸 SNAPSHOTS:"
|
||
sudo zfs list -t snapshot -r "$pool_name"
|
||
echo ""
|
||
fi
|
||
|
||
# Propiedades del pool
|
||
echo "⚙️ PROPIEDADES PRINCIPALES:"
|
||
echo "ARC Max: $(cat /sys/module/zfs/parameters/zfs_arc_max 2>/dev/null || echo 'No configurado')"
|
||
sudo zpool get all "$pool_name" | grep -E "ashift|feature|autoreplace|failmode"
|
||
}
|
||
|
||
# Ejecutar función principal
|
||
main "$@" |