mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-06-28 04:06:54 +00:00
add script disk passthrough to ct
This commit is contained in:
parent
70b9ab37be
commit
36c926dd2f
@ -1,478 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Configuración
|
||||
SCRIPT_VERSION="1.3"
|
||||
LOG_FILE="/var/log/proxmox_backup_restore.log"
|
||||
|
||||
# Colores para salida
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Variable global para el modo de interfaz
|
||||
INTERFACE_MODE=""
|
||||
|
||||
# Funciones de utilidad
|
||||
log() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
|
||||
echo -e "$1"
|
||||
}
|
||||
|
||||
error() {
|
||||
log "${RED}ERROR: $1${NC}"
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
whiptail --title "Error" --msgbox "$1" 8 78
|
||||
else
|
||||
echo -e "${RED}ERROR: $1${NC}"
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
success() {
|
||||
log "${GREEN}$1${NC}"
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
whiptail --title "Éxito" --msgbox "$1" 8 78
|
||||
else
|
||||
echo -e "${GREEN}$1${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
warning() {
|
||||
log "${YELLOW}ADVERTENCIA: $1${NC}"
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
whiptail --title "Advertencia" --msgbox "$1" 8 78
|
||||
else
|
||||
echo -e "${YELLOW}ADVERTENCIA: $1${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Función para seleccionar el modo de interfaz
|
||||
select_interface_mode() {
|
||||
if [ "$(tty)" = "/dev/tty1" ] || [ "$(tty)" = "/dev/console" ]; then
|
||||
echo "Ejecutando en consola física. Usando interfaz de texto."
|
||||
INTERFACE_MODE="echo"
|
||||
elif command -v whiptail >/dev/null 2>&1; then
|
||||
echo "Ejecutando en terminal remota. Usando interfaz whiptail."
|
||||
INTERFACE_MODE="whiptail"
|
||||
else
|
||||
echo "whiptail no está disponible. Usando interfaz de texto."
|
||||
INTERFACE_MODE="echo"
|
||||
fi
|
||||
}
|
||||
|
||||
# Función para mostrar el menú principal
|
||||
show_main_menu() {
|
||||
while true; do
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
CHOICE=$(whiptail --title "Proxmox Backup & Restore Tool" --menu "Seleccione una opción:" 15 60 3 \
|
||||
"1" "Realizar copia de seguridad" \
|
||||
"2" "Restaurar copia de seguridad" \
|
||||
"3" "Salir" 3>&1 1>&2 2>&3)
|
||||
else
|
||||
echo "Proxmox Backup & Restore Tool"
|
||||
echo "1. Realizar copia de seguridad"
|
||||
echo "2. Restaurar copia de seguridad"
|
||||
echo "3. Salir"
|
||||
read -p "Seleccione una opción: " CHOICE
|
||||
fi
|
||||
|
||||
case $CHOICE in
|
||||
1) perform_backup ;;
|
||||
2) perform_restore ;;
|
||||
3) exit 0 ;;
|
||||
*) echo "Opción no válida. Por favor, intente de nuevo." ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Función para seleccionar la ubicación de la copia de seguridad
|
||||
select_backup_location() {
|
||||
local options=()
|
||||
local i=1
|
||||
|
||||
# Ubicaciones recomendadas
|
||||
options+=("/root/backups/" "/var/lib/vz/dump/")
|
||||
|
||||
# Detectar discos USB
|
||||
local usb_disks=$(lsblk -ndo NAME,TRAN,SIZE | awk '$2=="usb" {print "/dev/"$1}')
|
||||
options+=($usb_disks)
|
||||
|
||||
# Otros discos disponibles
|
||||
local other_disks=$(lsblk -ndo NAME,SIZE,FSTYPE | grep -vE "^(sd[a-z]|nvme[0-9]n[0-9])" | awk '$3!="" {print "/dev/"$1}')
|
||||
options+=($other_disks)
|
||||
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
BACKUP_LOCATION=$(whiptail --title "Seleccionar ubicación de copia de seguridad" \
|
||||
--menu "Elija dónde guardar la copia de seguridad:" 20 78 10 \
|
||||
$(for i in "${!options[@]}"; do echo "$i ${options[$i]}"; done) \
|
||||
"C" "Introducir ruta personalizada" 3>&1 1>&2 2>&3)
|
||||
else
|
||||
echo "Seleccionar ubicación de copia de seguridad:"
|
||||
for i in "${!options[@]}"; do
|
||||
echo "$i. ${options[$i]}"
|
||||
done
|
||||
echo "C. Introducir ruta personalizada"
|
||||
read -p "Elija dónde guardar la copia de seguridad: " BACKUP_LOCATION
|
||||
fi
|
||||
|
||||
if [[ $BACKUP_LOCATION == "C" ]]; then
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
BACKUP_LOCATION=$(whiptail --inputbox "Introduzca la ruta personalizada:" 8 78 "/mnt/backup" --title "Ruta personalizada" 3>&1 1>&2 2>&3)
|
||||
else
|
||||
read -p "Introduzca la ruta personalizada: " BACKUP_LOCATION
|
||||
fi
|
||||
elif [[ $BACKUP_LOCATION =~ ^[0-9]+$ ]]; then
|
||||
BACKUP_LOCATION=${options[$BACKUP_LOCATION]}
|
||||
fi
|
||||
|
||||
echo "$BACKUP_LOCATION"
|
||||
}
|
||||
|
||||
# Función para realizar la copia de seguridad
|
||||
perform_backup() {
|
||||
local BACKUP_LOCATION=$(select_backup_location)
|
||||
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
local BACKUP_TYPE=$(whiptail --title "Tipo de copia de seguridad" --menu "Seleccione el tipo de copia de seguridad:" 15 60 2 \
|
||||
"1" "Copia de seguridad total" \
|
||||
"2" "Copia de seguridad personalizada" 3>&1 1>&2 2>&3)
|
||||
else
|
||||
echo "Tipo de copia de seguridad:"
|
||||
echo "1. Copia de seguridad total"
|
||||
echo "2. Copia de seguridad personalizada"
|
||||
read -p "Seleccione el tipo de copia de seguridad: " BACKUP_TYPE
|
||||
fi
|
||||
|
||||
local TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
||||
local BACKUP_PATH="${BACKUP_LOCATION}/proxmox_backup_${TIMESTAMP}"
|
||||
mkdir -p "$BACKUP_PATH" || error "No se pudo crear el directorio de copia de seguridad."
|
||||
|
||||
case $BACKUP_TYPE in
|
||||
1) backup_total "$BACKUP_PATH" ;;
|
||||
2) backup_personalizada "$BACKUP_PATH" ;;
|
||||
*) error "Opción no válida." ;;
|
||||
esac
|
||||
|
||||
# Guardar versión de Proxmox
|
||||
pveversion > "$BACKUP_PATH/pve_version.txt"
|
||||
|
||||
# Guardar mapa de rutas de almacenamiento
|
||||
pvesm status --output-format=json > "$BACKUP_PATH/storage_paths.json"
|
||||
|
||||
success "Copia de seguridad completada en $BACKUP_PATH"
|
||||
}
|
||||
|
||||
# Función para realizar copia de seguridad total
|
||||
backup_total() {
|
||||
local BACKUP_PATH=$1
|
||||
log "Iniciando copia de seguridad total..."
|
||||
|
||||
# Copiar configuraciones de Proxmox
|
||||
cp -r /etc/pve "$BACKUP_PATH/etc_pve" || warning "Error al copiar /etc/pve"
|
||||
cp -r /etc/network "$BACKUP_PATH/etc_network" || warning "Error al copiar /etc/network"
|
||||
cp /etc/hostname "$BACKUP_PATH/etc_hostname" || warning "Error al copiar /etc/hostname"
|
||||
cp /etc/hosts "$BACKUP_PATH/etc_hosts" || warning "Error al copiar /etc/hosts"
|
||||
|
||||
# Copiar logs relevantes
|
||||
mkdir -p "$BACKUP_PATH/var_log"
|
||||
cp /var/log/pveam.log "$BACKUP_PATH/var_log/" || warning "Error al copiar pveam.log"
|
||||
cp /var/log/pvedaemon.log "$BACKUP_PATH/var_log/" || warning "Error al copiar pvedaemon.log"
|
||||
|
||||
# Copiar configuraciones de almacenamiento
|
||||
cp /etc/pve/storage.cfg "$BACKUP_PATH/storage.cfg" || warning "Error al copiar storage.cfg"
|
||||
|
||||
# Copiar configuraciones de usuarios y permisos
|
||||
cp /etc/pve/user.cfg "$BACKUP_PATH/user.cfg" || warning "Error al copiar user.cfg"
|
||||
cp /etc/pve/groups.cfg "$BACKUP_PATH/groups.cfg" || warning "Error al copiar groups.cfg"
|
||||
|
||||
# Copiar configuraciones de firewall
|
||||
cp -r /etc/pve/firewall "$BACKUP_PATH/firewall" || warning "Error al copiar configuraciones de firewall"
|
||||
|
||||
# Copiar metadatos de VMs y contenedores (sin incluir discos o snapshots)
|
||||
mkdir -p "$BACKUP_PATH/vms_metadata"
|
||||
for vmid in $(qm list | awk '{if(NR>1) print $1}'); do
|
||||
qm config $vmid > "$BACKUP_PATH/vms_metadata/vm_${vmid}.conf"
|
||||
done
|
||||
|
||||
mkdir -p "$BACKUP_PATH/cts_metadata"
|
||||
for ctid in $(pct list | awk '{if(NR>1) print $1}'); do
|
||||
pct config $ctid > "$BACKUP_PATH/cts_metadata/ct_${ctid}.conf"
|
||||
done
|
||||
|
||||
log "Copia de seguridad total completada."
|
||||
}
|
||||
|
||||
# Función para realizar copia de seguridad personalizada
|
||||
backup_personalizada() {
|
||||
local BACKUP_PATH=$1
|
||||
log "Iniciando copia de seguridad personalizada..."
|
||||
|
||||
local options=(
|
||||
"1" "Configuración del sistema Proxmox" ON
|
||||
"2" "Configuraciones de almacenamiento" ON
|
||||
"3" "Configuraciones de red" ON
|
||||
"4" "Usuarios y permisos" ON
|
||||
"5" "Logs del sistema relevantes" OFF
|
||||
"6" "Configuraciones de firewall" ON
|
||||
"7" "Metadatos de VMs y contenedores" ON
|
||||
)
|
||||
|
||||
local SELECTED_OPTIONS
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
SELECTED_OPTIONS=$(whiptail --title "Selección de componentes" \
|
||||
--checklist "Seleccione los componentes a respaldar:" 20 78 7 \
|
||||
"${options[@]}" 3>&1 1>&2 2>&3)
|
||||
else
|
||||
echo "Selección de componentes a respaldar:"
|
||||
for ((i=0; i<${#options[@]}; i+=3)); do
|
||||
echo "${options[i]}. ${options[i+1]}"
|
||||
done
|
||||
read -p "Ingrese los números de los componentes a respaldar (separados por espacio): " -a selections
|
||||
for sel in "${selections[@]}"; do
|
||||
SELECTED_OPTIONS+="$sel "
|
||||
done
|
||||
fi
|
||||
|
||||
for option in $SELECTED_OPTIONS; do
|
||||
case $option in
|
||||
1)
|
||||
cp -r /etc/pve "$BACKUP_PATH/etc_pve" || warning "Error al copiar /etc/pve"
|
||||
cp /etc/hostname "$BACKUP_PATH/etc_hostname" || warning "Error al copiar /etc/hostname"
|
||||
cp /etc/hosts "$BACKUP_PATH/etc_hosts" || warning "Error al copiar /etc/hosts"
|
||||
;;
|
||||
2)
|
||||
cp /etc/pve/storage.cfg "$BACKUP_PATH/storage.cfg" || warning "Error al copiar storage.cfg"
|
||||
;;
|
||||
3)
|
||||
cp -r /etc/network "$BACKUP_PATH/etc_network" || warning "Error al copiar /etc/network"
|
||||
;;
|
||||
4)
|
||||
cp /etc/pve/user.cfg "$BACKUP_PATH/user.cfg" || warning "Error al copiar user.cfg"
|
||||
cp /etc/pve/groups.cfg "$BACKUP_PATH/groups.cfg" || warning "Error al copiar groups.cfg"
|
||||
;;
|
||||
5)
|
||||
mkdir -p "$BACKUP_PATH/var_log"
|
||||
cp /var/log/pveam.log "$BACKUP_PATH/var_log/" || warning "Error al copiar pveam.log"
|
||||
cp /var/log/pvedaemon.log "$BACKUP_PATH/var_log/" || warning "Error al copiar pvedaemon.log"
|
||||
;;
|
||||
6)
|
||||
cp -r /etc/pve/firewall "$BACKUP_PATH/firewall" || warning "Error al copiar configuraciones de firewall"
|
||||
;;
|
||||
7)
|
||||
mkdir -p "$BACKUP_PATH/vms_metadata"
|
||||
for vmid in $(qm list | awk '{if(NR>1) print $1}'); do
|
||||
qm config $vmid > "$BACKUP_PATH/vms_metadata/vm_${vmid}.conf"
|
||||
done
|
||||
|
||||
mkdir -p "$BACKUP_PATH/cts_metadata"
|
||||
for ctid in $(pct list | awk '{if(NR>1) print $1}'); do
|
||||
pct config $ctid > "$BACKUP_PATH/cts_metadata/ct_${ctid}.conf"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log "Copia de seguridad personalizada completada."
|
||||
}
|
||||
|
||||
# Función para restaurar desde una copia de seguridad
|
||||
perform_restore() {
|
||||
local BACKUP_LOCATION
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
BACKUP_LOCATION=$(whiptail --inputbox "Introduzca la ruta de la copia de seguridad:" 8 78 "/root/proxmox_backups" --title "Restauración" 3>&1 1>&2 2>&3)
|
||||
else
|
||||
read -p "Introduzca la ruta de la copia de seguridad: " BACKUP_LOCATION
|
||||
fi
|
||||
|
||||
local backups=($(ls -d ${BACKUP_LOCATION}/proxmox_backup_* 2>/dev/null))
|
||||
if [ ${#backups[@]} -eq 0 ]; then
|
||||
error "No se encontraron copias de seguridad en $BACKUP_LOCATION"
|
||||
fi
|
||||
|
||||
local SELECTED_BACKUP
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
local options=()
|
||||
for i in "${!backups[@]}"; do
|
||||
options+=("$i" "$(basename ${backups[$i]})")
|
||||
done
|
||||
SELECTED_BACKUP=$(whiptail --title "Seleccionar copia de seguridad" \
|
||||
--menu "Elija la copia de seguridad a restaurar:" 20 78 10 \
|
||||
"${options[@]}" 3>&1 1>&2 2>&3)
|
||||
else
|
||||
echo "Copias de seguridad disponibles:"
|
||||
for i in "${!backups[@]}"; do
|
||||
echo "$i. $(basename ${backups[$i]})"
|
||||
done
|
||||
read -p "Elija la copia de seguridad a restaurar: " SELECTED_BACKUP
|
||||
fi
|
||||
|
||||
local BACKUP_PATH="${backups[$SELECTED_BACKUP]}"
|
||||
|
||||
# Verificar compatibilidad de versiones
|
||||
if ! verify_pve_version "$BACKUP_PATH"; then
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
if ! whiptail --yesno "La versión de Proxmox es diferente. ¿Desea continuar con la restauración?" 8 78; then
|
||||
error "Restauración cancelada debido a diferencia de versiones."
|
||||
fi
|
||||
else
|
||||
read -p "La versión de Proxmox es diferente. ¿Desea continuar con la restauración? (s/n): " response
|
||||
if [[ ! $response =~ ^[Ss]$ ]]; then
|
||||
error "Restauración cancelada debido a diferencia de versiones."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Verificar cambios de hardware
|
||||
if ! verify_hardware "$BACKUP_PATH"; then
|
||||
warning "Se detectaron cambios en el hardware. Revise el informe en $BACKUP_PATH/hardware_changes.txt"
|
||||
fi
|
||||
|
||||
# Verificar y ajustar paths de almacenamiento
|
||||
if ! adjust_storage_paths "$BACKUP_PATH"; then
|
||||
warning "Algunas rutas de almacenamiento han cambiado. Revise y ajuste manualmente si es necesario."
|
||||
fi
|
||||
|
||||
# Realizar la restauración
|
||||
restore_files "$BACKUP_PATH"
|
||||
|
||||
success "Restauración completada. Se recomienda reiniciar el sistema."
|
||||
}
|
||||
|
||||
# Función para verificar la versión de Proxmox
|
||||
verify_pve_version() {
|
||||
local BACKUP_PATH=$1
|
||||
local backup_version=$(cat "$BACKUP_PATH/pve_version.txt")
|
||||
local current_version=$(pveversion | grep "pve-manager/")
|
||||
|
||||
if [ "$backup_version" != "$current_version" ]; then
|
||||
warning "La versión de Proxmox actual ($current_version) es diferente de la versión del backup ($backup_version)."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Función para verificar cambios de hardware
|
||||
verify_hardware() {
|
||||
local BACKUP_PATH=$1
|
||||
local current_hw=$(lshw -short)
|
||||
local backup_hw_file="$BACKUP_PATH/hardware_info.txt"
|
||||
|
||||
if [ ! -f "$backup_hw_file" ]; then
|
||||
warning "No se encontró información de hardware en la copia de seguridad."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local backup_hw=$(cat "$backup_hw_file")
|
||||
if [ "$current_hw" != "$backup_hw" ]; then
|
||||
diff <(echo "$backup_hw") <(echo "$current_hw") > "$BACKUP_PATH/hardware_changes.txt"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Función para ajustar rutas de almacenamiento
|
||||
adjust_storage_paths() {
|
||||
local BACKUP_PATH=$1
|
||||
local old_paths_file="$BACKUP_PATH/storage_paths.json"
|
||||
local new_paths=$(pvesm status --output-format=json)
|
||||
|
||||
if [ ! -f "$old_paths_file" ]; then
|
||||
warning "No se encontró información de rutas de almacenamiento en la copia de seguridad."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local old_paths=$(cat "$old_paths_file")
|
||||
if [ "$new_paths" != "$old_paths" ]; then
|
||||
echo "Se detectaron cambios en las rutas de almacenamiento:"
|
||||
diff <(echo "$old_paths") <(echo "$new_paths")
|
||||
|
||||
if [ "$INTERFACE_MODE" = "whiptail" ]; then
|
||||
if whiptail --yesno "¿Desea ajustar automáticamente las rutas de almacenamiento?" 8 78; then
|
||||
# Aquí iría la lógica para ajustar automáticamente las rutas
|
||||
# Por ejemplo, actualizando los archivos de configuración relevantes
|
||||
warning "Ajuste automático de rutas no implementado. Por favor, revise manualmente."
|
||||
else
|
||||
warning "Las rutas de almacenamiento deben ajustarse manualmente."
|
||||
fi
|
||||
else
|
||||
read -p "¿Desea ajustar automáticamente las rutas de almacenamiento? (s/n): " response
|
||||
if [[ $response =~ ^[Ss]$ ]]; then
|
||||
# Aquí iría la lógica para ajustar automáticamente las rutas
|
||||
warning "Ajuste automático de rutas no implementado. Por favor, revise manualmente."
|
||||
else
|
||||
warning "Las rutas de almacenamiento deben ajustarse manualmente."
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Función para restaurar archivos
|
||||
restore_files() {
|
||||
local BACKUP_PATH=$1
|
||||
log "Iniciando restauración de archivos..."
|
||||
|
||||
# Restaurar configuraciones de Proxmox
|
||||
if [ -d "$BACKUP_PATH/etc_pve" ]; then
|
||||
cp -r "$BACKUP_PATH/etc_pve"/* /etc/pve/ || warning "Error al restaurar /etc/pve"
|
||||
fi
|
||||
|
||||
if [ -d "$BACKUP_PATH/etc_network" ]; then
|
||||
cp -r "$BACKUP_PATH/etc_network"/* /etc/network/ || warning "Error al restaurar /etc/network"
|
||||
fi
|
||||
|
||||
if [ -f "$BACKUP_PATH/etc_hostname" ]; then
|
||||
cp "$BACKUP_PATH/etc_hostname" /etc/hostname || warning "Error al restaurar /etc/hostname"
|
||||
fi
|
||||
|
||||
if [ -f "$BACKUP_PATH/etc_hosts" ]; then
|
||||
cp "$BACKUP_PATH/etc_hosts" /etc/hosts || warning "Error al restaurar /etc/hosts"
|
||||
fi
|
||||
|
||||
# Restaurar logs
|
||||
if [ -d "$BACKUP_PATH/var_log" ]; then
|
||||
cp "$BACKUP_PATH/var_log"/* /var/log/ || warning "Error al restaurar logs"
|
||||
fi
|
||||
|
||||
# Restaurar configuraciones de almacenamiento
|
||||
if [ -f "$BACKUP_PATH/storage.cfg" ]; then
|
||||
cp "$BACKUP_PATH/storage.cfg" /etc/pve/storage.cfg || warning "Error al restaurar storage.cfg"
|
||||
fi
|
||||
|
||||
# Restaurar configuraciones de usuarios y permisos
|
||||
if [ -f "$BACKUP_PATH/user.cfg" ]; then
|
||||
cp "$BACKUP_PATH/user.cfg" /etc/pve/user.cfg || warning "Error al restaurar user.cfg"
|
||||
fi
|
||||
|
||||
if [ -f "$BACKUP_PATH/groups.cfg" ]; then
|
||||
cp "$BACKUP_PATH/groups.cfg" /etc/pve/groups.cfg || warning "Error al restaurar groups.cfg"
|
||||
fi
|
||||
|
||||
# Restaurar configuraciones de firewall
|
||||
if [ -d "$BACKUP_PATH/firewall" ]; then
|
||||
cp -r "$BACKUP_PATH/firewall"/* /etc/pve/firewall/ || warning "Error al restaurar configuraciones de firewall"
|
||||
fi
|
||||
|
||||
# Restaurar metadatos de VMs y contenedores
|
||||
if [ -d "$BACKUP_PATH/vms_metadata" ]; then
|
||||
for conf in "$BACKUP_PATH/vms_metadata"/*.conf; do
|
||||
vmid=$(basename "$conf" .conf | cut -d'_' -f2)
|
||||
qm importconfig $vmid "$conf" || warning "Error al restaurar configuración de VM $vmid"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -d "$BACKUP_PATH/cts_metadata" ]; then
|
||||
for conf in "$BACKUP_PATH/cts_metadata"/*.conf; do
|
||||
ctid=$(basename "$conf" .conf | cut -d'_' -f2)
|
||||
pct importconfig $ctid "$conf" || warning "Error al restaurar configuración de CT $ctid"
|
||||
done
|
||||
fi
|
||||
|
||||
log "Restauración de archivos completada."
|
||||
}
|
||||
|
||||
# Iniciar el script
|
||||
select_interface_mode
|
||||
show_main_menu
|
@ -1,100 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
DUMP_DIR="/var/lib/vz/dump"
|
||||
STORAGE_CFG="/etc/pve/storage.cfg"
|
||||
|
||||
# Función para realizar copia de seguridad del archivo storage.cfg
|
||||
backup_storage_cfg() {
|
||||
BACKUP_FILE="${DUMP_DIR}/storage.cfg_$(date +%Y%m%d%H%M%S).bak"
|
||||
cp "$STORAGE_CFG" "$BACKUP_FILE"
|
||||
whiptail --title "Copia de Seguridad" --msgbox "Se ha creado una copia de seguridad en: $BACKUP_FILE" 8 40
|
||||
}
|
||||
|
||||
# Función para comprobar y reparar el archivo storage.cfg
|
||||
reparar_storage_cfg() {
|
||||
whiptail --title "Comprobación de Almacenamientos" --msgbox "Comprobando consistencia de los volúmenes de almacenamiento..." 8 40
|
||||
|
||||
VG_LIST=$(vgs --noheadings -o vg_name)
|
||||
while read -r LINE; do
|
||||
if [[ "$LINE" =~ vgname ]]; then
|
||||
VG_NAME=$(echo "$LINE" | awk '{print $NF}')
|
||||
if ! echo "$VG_LIST" | grep -q "$VG_NAME"; then
|
||||
echo "El volumen $VG_NAME no existe, eliminando entrada..."
|
||||
sed -i "/vgname $VG_NAME/,/nodes/d" "$STORAGE_CFG"
|
||||
fi
|
||||
fi
|
||||
done < "$STORAGE_CFG"
|
||||
|
||||
whiptail --title "Reparación Completada" --msgbox "La comprobación de consistencia ha finalizado. Se eliminaron las entradas no válidas." 8 40
|
||||
}
|
||||
|
||||
# Función para restaurar copia de seguridad del archivo storage.cfg
|
||||
restaurar_backup() {
|
||||
BACKUP_FILE=$(whiptail --title "Seleccionar Copia de Seguridad" --menu "Selecciona la copia de seguridad a restaurar:" 15 60 8 $(ls "$DUMP_DIR"/storage.cfg_*.bak 2>/dev/null) 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$BACKUP_FILE" ]; then
|
||||
whiptail --title "Error" --msgbox "No se seleccionó ninguna copia de seguridad." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp "$BACKUP_FILE" "$STORAGE_CFG"
|
||||
whiptail --title "Restauración Completada" --msgbox "Se ha restaurado el archivo storage.cfg desde la copia de seguridad: $BACKUP_FILE" 8 40
|
||||
|
||||
reparar_storage_cfg
|
||||
}
|
||||
|
||||
# Función para reconectar los grupos de volúmenes
|
||||
reconectar_volumenes() {
|
||||
whiptail --title "Reconectar discos en Proxmox" --msgbox "Este proceso activará los volúmenes LVM y LVM-thin en su sistema." 12 60
|
||||
|
||||
VG_LIST=$(vgscan --ignorelockingfailure --reportformat json | jq -r '.report[0].vg[].vg_name')
|
||||
|
||||
if [ -z "$VG_LIST" ]; then
|
||||
whiptail --title "Error" --msgbox "No se detectaron grupos de volúmenes LVM en el sistema." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VG_SELECCIONADOS=$(whiptail --title "Seleccionar Grupos de Volúmenes" --checklist "Selecciona los grupos de volúmenes que deseas activar:" 20 60 10 $(for vg in $VG_LIST; do echo "$vg OFF"; done) 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$VG_SELECCIONADOS" ]; then
|
||||
whiptail --title "Error" --msgbox "No se seleccionó ningún grupo de volúmenes." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for VG in $VG_SELECCIONADOS; do
|
||||
VG=$(echo "$VG" | tr -d '"')
|
||||
vgchange -ay "$VG"
|
||||
done
|
||||
|
||||
whiptail --title "Volúmenes Activados" --msgbox "Los grupos de volúmenes seleccionados se activaron correctamente." 8 40
|
||||
|
||||
whiptail --title "Escanear VM" --infobox "Rescaneando las imágenes de disco y volúmenes..." 8 40
|
||||
qm rescan
|
||||
|
||||
whiptail --title "Finalizado" --msgbox "Los volúmenes y las imágenes de disco fueron reconocidos y están disponibles para usar en Proxmox." 8 40
|
||||
}
|
||||
|
||||
# Menú principal
|
||||
OPTION=$(whiptail --title "Gestor de Almacenamiento Proxmox" --menu "Selecciona una opción:" 15 60 4 \
|
||||
"1" "Realizar copia de seguridad del archivo storage.cfg" \
|
||||
"2" "Restaurar copia de seguridad y comprobar consistencia" \
|
||||
"3" "Reparar archivo storage.cfg si se han cambiado discos" \
|
||||
"4" "Reconectar grupos de volúmenes LVM/LVM-thin" 3>&1 1>&2 2>&3)
|
||||
|
||||
case $OPTION in
|
||||
1)
|
||||
backup_storage_cfg
|
||||
;;
|
||||
2)
|
||||
restaurar_backup
|
||||
;;
|
||||
3)
|
||||
reparar_storage_cfg
|
||||
;;
|
||||
4)
|
||||
reconectar_volumenes
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
385
scripts/disk-passthrough_ct.sh
Normal file
385
scripts/disk-passthrough_ct.sh
Normal file
@ -0,0 +1,385 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenu CT - A menu-driven script for Proxmox CT management
|
||||
# ==========================================================
|
||||
# Based on ProxMenu by MacRimi
|
||||
# Modified for Proxmox Containers
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows users to assign physical disks to existing
|
||||
# Proxmox containers (CTs) through an interactive menu.
|
||||
# - Detects the system disk and excludes it from selection.
|
||||
# - Lists all available CTs for the user to choose from.
|
||||
# - Identifies and displays unassigned physical disks.
|
||||
# - Allows the user to select multiple disks and attach them to a CT.
|
||||
# - Configures the selected disks for the CT and verifies the assignment.
|
||||
# ==========================================================
|
||||
|
||||
|
||||
# Configuration ============================================
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
VENV_PATH="/opt/googletrans-env"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
load_language
|
||||
initialize_cache
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
get_disk_info() {
|
||||
local disk=$1
|
||||
MODEL=$(lsblk -dn -o MODEL "$disk" | xargs)
|
||||
SIZE=$(lsblk -dn -o SIZE "$disk" | xargs)
|
||||
echo "$MODEL" "$SIZE"
|
||||
}
|
||||
|
||||
|
||||
|
||||
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
|
||||
if [ -z "$CT_LIST" ]; then
|
||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No CTs available in the system.")" 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
CTID=$(whiptail --title "$(translate "Select CT")" --menu "$(translate "Select the CT to which you want to add disks:")" 15 60 8 $CT_LIST 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$CTID" ]; then
|
||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No CT was selected.")" 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CTID=$(echo "$CTID" | tr -d '"')
|
||||
|
||||
msg_ok "$(translate "CT selected successfully.")"
|
||||
|
||||
CT_STATUS=$(pct status "$CTID" | awk '{print $2}')
|
||||
if [ "$CT_STATUS" == "running" ]; then
|
||||
whiptail --title "$(translate "Warning")" --msgbox "$(translate "The CT is powered on. Turn it off before adding disks.")" 12 60
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##########################################
|
||||
|
||||
msg_info "$(translate "Detecting available disks...")"
|
||||
|
||||
USED_DISKS=$(lsblk -n -o PKNAME,TYPE | grep 'lvm' | awk '{print "/dev/" $1}')
|
||||
MOUNTED_DISKS=$(lsblk -ln -o NAME,MOUNTPOINT | awk '$2!="" {print "/dev/" $1}')
|
||||
|
||||
ZFS_DISKS=""
|
||||
ZFS_RAW=$(zpool list -v -H 2>/dev/null | awk '{print $1}' | grep -v '^NAME$' | grep -v '^-' | grep -v '^mirror')
|
||||
|
||||
for entry in $ZFS_RAW; do
|
||||
path=""
|
||||
if [[ "$entry" == wwn-* || "$entry" == ata-* ]]; then
|
||||
if [ -e "/dev/disk/by-id/$entry" ]; then
|
||||
path=$(readlink -f "/dev/disk/by-id/$entry")
|
||||
fi
|
||||
elif [[ "$entry" == /dev/* ]]; then
|
||||
path="$entry"
|
||||
fi
|
||||
|
||||
if [ -n "$path" ]; then
|
||||
base_disk=$(lsblk -no PKNAME "$path" 2>/dev/null)
|
||||
if [ -n "$base_disk" ]; then
|
||||
ZFS_DISKS+="/dev/$base_disk"$'\n'
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
ZFS_DISKS=$(echo "$ZFS_DISKS" | sort -u)
|
||||
|
||||
is_disk_in_use() {
|
||||
local disk="$1"
|
||||
|
||||
while read -r part fstype; do
|
||||
case "$fstype" in
|
||||
zfs_member|linux_raid_member)
|
||||
return 0 ;;
|
||||
esac
|
||||
|
||||
if echo "$MOUNTED_DISKS" | grep -q "/dev/$part"; then
|
||||
return 0
|
||||
fi
|
||||
done < <(lsblk -ln -o NAME,FSTYPE "$disk" | tail -n +2)
|
||||
|
||||
if echo "$USED_DISKS" | grep -q "$disk" || echo "$ZFS_DISKS" | grep -q "$disk"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
FREE_DISKS=()
|
||||
|
||||
LVM_DEVICES=$(pvs --noheadings -o pv_name | xargs -n1 readlink -f | sort -u)
|
||||
RAID_ACTIVE=$(grep -Po 'md\d+\s*:\s*active\s+raid[0-9]+' /proc/mdstat | awk '{print $1}' | sort -u)
|
||||
|
||||
while read -r DISK; do
|
||||
[[ "$DISK" =~ /dev/zd ]] && continue
|
||||
|
||||
INFO=($(get_disk_info "$DISK"))
|
||||
MODEL="${INFO[@]::${#INFO[@]}-1}"
|
||||
SIZE="${INFO[-1]}"
|
||||
LABEL=""
|
||||
SHOW_DISK=true
|
||||
|
||||
IS_MOUNTED=false
|
||||
IS_RAID=false
|
||||
IS_ZFS=false
|
||||
IS_LVM=false
|
||||
|
||||
while read -r part fstype; do
|
||||
[[ "$fstype" == "zfs_member" ]] && IS_ZFS=true
|
||||
[[ "$fstype" == "linux_raid_member" ]] && IS_RAID=true
|
||||
[[ "$fstype" == "LVM2_member" ]] && IS_LVM=true
|
||||
if grep -q "/dev/$part" <<< "$MOUNTED_DISKS"; then
|
||||
IS_MOUNTED=true
|
||||
fi
|
||||
done < <(lsblk -ln -o NAME,FSTYPE "$DISK" | tail -n +2)
|
||||
|
||||
REAL_PATH=$(readlink -f "$DISK")
|
||||
if echo "$LVM_DEVICES" | grep -qFx "$REAL_PATH"; then
|
||||
IS_MOUNTED=true
|
||||
fi
|
||||
|
||||
if $IS_RAID && grep -q "$DISK" <<< "$(cat /proc/mdstat)"; then
|
||||
if grep -q "active raid" /proc/mdstat; then
|
||||
SHOW_DISK=false
|
||||
fi
|
||||
fi
|
||||
|
||||
if $IS_ZFS; then
|
||||
SHOW_DISK=false
|
||||
fi
|
||||
|
||||
if $IS_MOUNTED; then
|
||||
SHOW_DISK=false
|
||||
fi
|
||||
|
||||
if pct config "$CTID" | grep -q "$DISK"; then
|
||||
SHOW_DISK=false
|
||||
fi
|
||||
|
||||
if $SHOW_DISK; then
|
||||
[[ "$IS_RAID" == true ]] && LABEL+=" ⚠ with partitions"
|
||||
[[ "$IS_LVM" == true ]] && LABEL+=" ⚠ LVM"
|
||||
[[ "$IS_ZFS" == true ]] && LABEL+=" ⚠ ZFS"
|
||||
|
||||
DESCRIPTION=$(printf "%-30s %10s%s" "$MODEL" "$SIZE" "$LABEL")
|
||||
FREE_DISKS+=("$DISK" "$DESCRIPTION" "OFF")
|
||||
fi
|
||||
done < <(lsblk -dn -e 7,11 -o PATH)
|
||||
|
||||
if [ "${#FREE_DISKS[@]}" -eq 0 ]; then
|
||||
cleanup
|
||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No disks available for this CT.")" 8 40
|
||||
clear
|
||||
exit 1
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Available disks detected.")"
|
||||
|
||||
######################################################
|
||||
|
||||
MAX_WIDTH=$(printf "%s\n" "${FREE_DISKS[@]}" | awk '{print length}' | sort -nr | head -n1)
|
||||
TOTAL_WIDTH=$((MAX_WIDTH + 20))
|
||||
|
||||
if [ $TOTAL_WIDTH -lt 70 ]; then
|
||||
TOTAL_WIDTH=70
|
||||
fi
|
||||
|
||||
SELECTED=$(whiptail --title "$(translate "Select Disks")" --radiolist \
|
||||
"$(translate "Select the disks you want to add:")" 20 $TOTAL_WIDTH 10 "${FREE_DISKS[@]}" 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$SELECTED" ]; then
|
||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No disks were selected.")" 10 $TOTAL_WIDTH
|
||||
clear
|
||||
exit 1
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Disks selected successfully.")"
|
||||
|
||||
DISKS_ADDED=0
|
||||
ERROR_MESSAGES=""
|
||||
SUCCESS_MESSAGES=""
|
||||
|
||||
msg_info "$(translate "Processing selected disks...")"
|
||||
|
||||
for DISK in $SELECTED; do
|
||||
DISK=$(echo "$DISK" | tr -d '"')
|
||||
DISK_INFO=$(get_disk_info "$DISK")
|
||||
|
||||
ASSIGNED_TO=""
|
||||
RUNNING_CTS=""
|
||||
|
||||
while read -r CT_ID CT_NAME; do
|
||||
if [[ "$CT_ID" =~ ^[0-9]+$ ]] && pct config "$CT_ID" | grep -q "$DISK"; then
|
||||
ASSIGNED_TO+="$CT_ID $CT_NAME\n"
|
||||
CT_STATUS=$(pct status "$CT_ID" | awk '{print $2}')
|
||||
if [ "$CT_STATUS" == "running" ]; then
|
||||
RUNNING_CTS+="$CT_ID $CT_NAME\n"
|
||||
fi
|
||||
fi
|
||||
done < <(pct list | awk 'NR>1 {print $1, $3}')
|
||||
|
||||
if [ -n "$RUNNING_CTS" ]; then
|
||||
ERROR_MESSAGES+="$(translate "The disk") $DISK_INFO $(translate "is in use by the following running CT(s):")\\n$RUNNING_CTS\\n\\n"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ -n "$ASSIGNED_TO" ]; then
|
||||
cleanup
|
||||
whiptail --title "$(translate "Disk Already Assigned")" --yesno "$(translate "The disk") $DISK_INFO $(translate "is already assigned to the following CT(s):")\\n$ASSIGNED_TO\\n\\n$(translate "Do you want to continue anyway?")" 15 70
|
||||
if [ $? -ne 0 ]; then
|
||||
sleep 1
|
||||
exec "$0"
|
||||
fi
|
||||
fi
|
||||
|
||||
cleanup
|
||||
|
||||
MOUNT_POINT=$(whiptail --title "$(translate "Mount Point")" --inputbox "$(translate "Enter the mount point for the disk (e.g., /mnt/disk_passthrough):")" 10 60 "/mnt/disk_passthrough" 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$MOUNT_POINT" ]; then
|
||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No mount point was specified.")" 8 40
|
||||
continue
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Mount point specified: $MOUNT_POINT")"
|
||||
|
||||
|
||||
whiptail --title "$(translate "Format Required")" --msgbox "$(translate "To use the disk with a mount point, it needs to be formatted.")" 8 70
|
||||
|
||||
FORMAT_TYPE=$(whiptail --title "$(translate "Select Format Type")" --menu "$(translate "Select the filesystem type for") $DISK_INFO:" 15 60 6 \
|
||||
"ext4" "$(translate "Extended Filesystem 4 (recommended)")" \
|
||||
"xfs" "$(translate "XFS Filesystem")" \
|
||||
"btrfs" "$(translate "Btrfs Filesystem")" 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$FORMAT_TYPE" ]; then
|
||||
whiptail --title "$(translate "Format Cancelled")" --msgbox "$(translate "Format operation cancelled. The disk will not be added.")" 8 60
|
||||
continue
|
||||
fi
|
||||
|
||||
whiptail --title "$(translate "WARNING")" --yesno "$(translate "WARNING: This operation will FORMAT the disk") $DISK_INFO $(translate "with") $FORMAT_TYPE.\\n\\n$(translate "ALL DATA ON THIS DISK WILL BE PERMANENTLY LOST!")\\n\\n$(translate "Are you sure you want to continue?")" 15 70
|
||||
if [ $? -ne 0 ]; then
|
||||
whiptail --title "$(translate "Format Cancelled")" --msgbox "$(translate "Format operation cancelled. The disk will not be added.")" 8 60
|
||||
continue
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if lsblk "$DISK" | grep -q "raid" || grep -q "${DISK##*/}" /proc/mdstat; then
|
||||
whiptail --title "$(translate "RAID Detected")" --msgbox "$(translate "The disk") $DISK_INFO $(translate "is part of a RAID array and cannot be added.")\\n\\n$(translate "To use this disk, you must first stop the RAID array with:")\\n\\nmdadm --stop /dev/mdX\\nmdadm --zero-superblock $DISK\\n\\n$(translate "After removing the RAID metadata, run this script again to add the disk.")" 15 70
|
||||
|
||||
continue
|
||||
fi
|
||||
|
||||
MOUNTED_PARTITIONS=$(lsblk -n -o NAME,MOUNTPOINT "$DISK" | awk '$2 != "" {print $1}')
|
||||
if [ -n "$MOUNTED_PARTITIONS" ]; then
|
||||
UNMOUNT_FAILED=false
|
||||
|
||||
if mount | grep -q "$DISK "; then
|
||||
umount -f "$DISK" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
umount -f -l "$DISK" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
UNMOUNT_FAILED=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
for PART in $MOUNTED_PARTITIONS; do
|
||||
|
||||
if [[ "$PART" == "${DISK##*/}"* ]]; then
|
||||
PART_PATH="/dev/$PART"
|
||||
else
|
||||
PART_PATH="/dev/$PART"
|
||||
fi
|
||||
|
||||
umount -f "$PART_PATH" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
umount -f -l "$PART_PATH" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
UNMOUNT_FAILED=true
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$UNMOUNT_FAILED" = true ]; then
|
||||
whiptail --title "$(translate "Unmount Failed")" --msgbox "$(translate "Failed to unmount") $DISK $(translate "or its partitions. Cannot format.")\\n\\n$(translate "The disk may be in use by the system or other processes.")" 12 70
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
echo -e "$(translate "Removing partition table to ensure clean formatting...")"
|
||||
dd if=/dev/zero of="$DISK" bs=512 count=1 conv=notrunc
|
||||
partprobe "$DISK"
|
||||
sleep 2
|
||||
|
||||
echo -e "$(translate "Formatting disk") $DISK_INFO $(translate "with") $FORMAT_TYPE..."
|
||||
|
||||
case "$FORMAT_TYPE" in
|
||||
"ext4")
|
||||
mkfs.ext4 -F "$DISK" ;;
|
||||
"xfs")
|
||||
mkfs.xfs -f "$DISK" ;;
|
||||
"btrfs")
|
||||
mkfs.btrfs -f "$DISK" ;;
|
||||
esac
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
whiptail --title "$(translate "Format Failed")" --msgbox "$(translate "Failed to format disk") $DISK_INFO $(translate "with") $FORMAT_TYPE.\\n\\n$(translate "The disk may be in use by the system or have hardware issues.")" 12 70
|
||||
continue
|
||||
else
|
||||
msg_ok "$(translate "Disk") $DISK_INFO $(translate "successfully formatted with") $FORMAT_TYPE."
|
||||
|
||||
partprobe "$DISK"
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
INDEX=0
|
||||
while pct config "$CTID" | grep -q "mp${INDEX}:"; do
|
||||
((INDEX++))
|
||||
done
|
||||
|
||||
##############################################################################
|
||||
|
||||
RESULT=$(pct set "$CTID" -mp${INDEX} "$DISK,mp=$MOUNT_POINT,backup=0" 2>&1)
|
||||
|
||||
##############################################################################
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
MESSAGE="$(translate "The disk") $DISK_INFO $(translate "has been successfully added to CT") $CTID $(translate "as a mount point at") $MOUNT_POINT."
|
||||
if [ -n "$ASSIGNED_TO" ]; then
|
||||
MESSAGE+="\\n\\n$(translate "WARNING: This disk is also assigned to the following CT(s):")\\n$ASSIGNED_TO"
|
||||
MESSAGE+="\\n$(translate "Make sure not to start CTs that share this disk at the same time to avoid data corruption.")"
|
||||
fi
|
||||
SUCCESS_MESSAGES+="$MESSAGE\\n\\n"
|
||||
((DISKS_ADDED++))
|
||||
else
|
||||
ERROR_MESSAGES+="$(translate "Could not add disk") $DISK_INFO $(translate "to CT") $CTID.\\n$(translate "Error:") $RESULT\\n\\n"
|
||||
fi
|
||||
done
|
||||
|
||||
msg_ok "$(translate "Disk processing completed.")"
|
||||
|
||||
if [ -n "$SUCCESS_MESSAGES" ]; then
|
||||
MSG_LINES=$(echo "$SUCCESS_MESSAGES" | wc -l)
|
||||
whiptail --title "$(translate "Successful Operations")" --msgbox "$SUCCESS_MESSAGES" 16 70
|
||||
fi
|
||||
|
||||
if [ -n "$ERROR_MESSAGES" ]; then
|
||||
whiptail --title "$(translate "Warnings and Errors")" --msgbox "$ERROR_MESSAGES" 16 70
|
||||
fi
|
||||
|
||||
exit 0
|
@ -1,366 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Variables globales
|
||||
CHANGES_MADE=0 # Inicializar cambios para verificar si es necesario reiniciar el contenedor
|
||||
NEED_REBOOT=0 # Controla si se requiere reinicio completo del servidor
|
||||
|
||||
# Colores para salida
|
||||
YW="\033[33m"
|
||||
GN="\033[1;92m"
|
||||
RD="\033[01;31m"
|
||||
CL="\033[m"
|
||||
|
||||
# Funciones auxiliares
|
||||
log() {
|
||||
echo -e "$(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
msg_info() {
|
||||
echo -ne " ${YW}[INFO] $1...${CL}"
|
||||
}
|
||||
msg_ok() {
|
||||
echo -e " ${GN}[OK] $1${CL}"
|
||||
}
|
||||
msg_error() {
|
||||
echo -e " ${RD}[ERROR] $1${CL}"
|
||||
}
|
||||
|
||||
# Validar que el contenedor seleccionado es válido
|
||||
validate_container_id() {
|
||||
if [ -z "$CONTAINER_ID" ]; then
|
||||
msg_error "ID del contenedor no definido. Asegúrate de seleccionar un contenedor primero."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Verificar la versión de Proxmox
|
||||
validate_pve_version() {
|
||||
if ! pveversion | grep -Eq "pve-manager/(8\\.[0-9]+)"; then
|
||||
msg_error "Esta versión de Proxmox no es compatible. Se requiere Proxmox VE 8.0 o superior."
|
||||
exit 1
|
||||
fi
|
||||
msg_ok "Versión de Proxmox compatible."
|
||||
}
|
||||
|
||||
# Función para reinicio
|
||||
restart_prompt() {
|
||||
if (whiptail --title "Reinicio requerido" --yesno "La instalación requiere un reinicio del servidor para que los cambios sean efectivos. ¿Deseas reiniciar ahora?" 8 58); then
|
||||
msg_info "Reiniciando el servidor..."
|
||||
reboot
|
||||
else
|
||||
msg_info "No se realizó el reinicio. Por favor, reinicia manualmente más tarde para aplicar los cambios."
|
||||
fi
|
||||
}
|
||||
|
||||
# Reinicio del servidor al final
|
||||
final_restart_prompt() {
|
||||
if [ "$NEED_REBOOT" -eq 1 ]; then
|
||||
msg_info "Se recomienda reiniciar el servidor para aplicar los cambios correctamente."
|
||||
restart_prompt
|
||||
fi
|
||||
}
|
||||
|
||||
# Selección del contenedor LXC
|
||||
select_container() {
|
||||
CONTAINERS=$(pct list | awk 'NR>1 {print $1, $3}' | xargs -n2)
|
||||
if [ -z "$CONTAINERS" ]; then
|
||||
msg_error "No hay contenedores disponibles en Proxmox."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONTAINER_ID=$(whiptail --title "Seleccionar Contenedor" \
|
||||
--menu "Selecciona el contenedor LXC:" 15 60 5 $CONTAINERS 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$CONTAINER_ID" ]; then
|
||||
msg_error "No se seleccionó ningún contenedor. Saliendo."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! pct list | awk 'NR>1 {print $1}' | grep -qw "$CONTAINER_ID"; then
|
||||
msg_error "El contenedor con ID $CONTAINER_ID no existe. Saliendo."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
msg_ok "Contenedor seleccionado: $CONTAINER_ID"
|
||||
}
|
||||
|
||||
# Validar y cambiar a privilegiado si es necesario
|
||||
ensure_privileged_container() {
|
||||
validate_container_id
|
||||
CONFIG_FILE="/etc/pve/lxc/${CONTAINER_ID}.conf"
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
msg_error "Archivo de configuración del contenedor $CONTAINER_ID no encontrado."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -q "^unprivileged: 1" "$CONFIG_FILE"; then
|
||||
msg_info "El contenedor es no privilegiado. Cambiando a privilegiado..."
|
||||
sed -i "s/^unprivileged: 1/unprivileged: 0/" "$CONFIG_FILE"
|
||||
STORAGE_TYPE=$(pct config "$CONTAINER_ID" | grep "^rootfs:" | awk -F, '{print $2}' | cut -d'=' -f2)
|
||||
if [[ "$STORAGE_TYPE" == "dir" ]]; then
|
||||
STORAGE_PATH=$(pct config "$CONTAINER_ID" | grep "^rootfs:" | awk '{print $2}' | cut -d',' -f1)
|
||||
chown -R root:root "$STORAGE_PATH"
|
||||
fi
|
||||
msg_ok "Contenedor cambiado a privilegiado."
|
||||
else
|
||||
msg_ok "El contenedor ya es privilegiado."
|
||||
fi
|
||||
}
|
||||
|
||||
# Verificar y configurar repositorios en el host
|
||||
verify_and_add_repos() {
|
||||
msg_info "Verificando y configurando repositorios necesarios en el host..."
|
||||
|
||||
if ! grep -q "pve-no-subscription" /etc/apt/sources.list /etc/apt/sources.list.d/* 2>/dev/null; then
|
||||
echo "deb http://download.proxmox.com/debian/pve $(lsb_release -sc) pve-no-subscription" | tee /etc/apt/sources.list.d/pve-no-subscription.list
|
||||
msg_ok "Repositorio pve-no-subscription añadido."
|
||||
else
|
||||
msg_ok "Repositorio pve-no-subscription ya configurado."
|
||||
fi
|
||||
|
||||
if ! grep -q "non-free-firmware" /etc/apt/sources.list; then
|
||||
echo "deb http://deb.debian.org/debian $(lsb_release -sc) main contrib non-free-firmware
|
||||
deb http://deb.debian.org/debian $(lsb_release -sc)-updates main contrib non-free-firmware
|
||||
deb http://security.debian.org/debian-security $(lsb_release -sc)-security main contrib non-free-firmware" | tee -a /etc/apt/sources.list
|
||||
msg_ok "Repositorios non-free-firmware añadidos."
|
||||
else
|
||||
msg_ok "Repositorios non-free-firmware ya configurados."
|
||||
fi
|
||||
|
||||
apt-get update
|
||||
# apt-get update &>/dev/null
|
||||
msg_ok "Repositorios verificados y actualizados."
|
||||
}
|
||||
|
||||
|
||||
# Configurar Coral TPU en el contenedor
|
||||
configure_lxc_for_coral() {
|
||||
ensure_privileged_container
|
||||
CONFIG_FILE="/etc/pve/lxc/${CONTAINER_ID}.conf"
|
||||
|
||||
# Verificar y agregar configuraciones solo si no existen
|
||||
if ! grep -Pq "^lxc.cgroup2.devices.allow: c 189:\* rwm # Coral USB$" "$CONFIG_FILE"; then
|
||||
echo "lxc.cgroup2.devices.allow: c 189:* rwm # Coral USB" >> "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
if ! grep -Pq "^lxc.mount.entry: /dev/bus/usb dev/bus/usb none bind,optional,create=dir$" "$CONFIG_FILE"; then
|
||||
echo "lxc.mount.entry: /dev/bus/usb dev/bus/usb none bind,optional,create=dir" >> "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
if ! grep -Pq "^lxc.mount.entry: /dev/apex_0 dev/apex_0 none bind,optional,create=file$" "$CONFIG_FILE"; then
|
||||
echo "lxc.mount.entry: /dev/apex_0 dev/apex_0 none bind,optional,create=file" >> "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
msg_ok "Configuración de Coral TPU (USB y M.2) añadida al contenedor $CONTAINER_ID."
|
||||
}
|
||||
|
||||
|
||||
# Configurar iGPU en el contenedor
|
||||
configure_lxc_for_igpu() {
|
||||
ensure_privileged_container
|
||||
CONFIG_FILE="/etc/pve/lxc/${CONTAINER_ID}.conf"
|
||||
|
||||
# Verificar y agregar configuraciones solo si no existen
|
||||
if ! grep -q "features: nesting=1" "$CONFIG_FILE"; then
|
||||
echo "features: nesting=1" >> "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
if ! grep -q "c 226:0 rwm" "$CONFIG_FILE"; then
|
||||
echo "lxc.cgroup2.devices.allow: c 226:0 rwm # iGPU" >> "$CONFIG_FILE"
|
||||
echo "lxc.cgroup2.devices.allow: c 226:128 rwm # iGPU" >> "$CONFIG_FILE"
|
||||
echo "lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir" >> "$CONFIG_FILE"
|
||||
echo "lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file" >> "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
if ! grep -q "c 29:0 rwm # Framebuffer" "$CONFIG_FILE"; then
|
||||
echo "lxc.cgroup2.devices.allow: c 29:0 rwm # Framebuffer" >> "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
if ! grep -q "lxc.mount.entry: /dev/fb0" "$CONFIG_FILE"; then
|
||||
echo "lxc.mount.entry: /dev/fb0 dev/fb0 none bind,optional,create=file" >> "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
msg_ok "Configuración de iGPU añadida al contenedor $CONTAINER_ID."
|
||||
}
|
||||
|
||||
|
||||
# Instalar controladores iGPU en el contenedor
|
||||
install_igpu_in_container() {
|
||||
msg_info "Instalando controladores de iGPU dentro del contenedor..."
|
||||
pct start "$CONTAINER_ID"
|
||||
pct exec "$CONTAINER_ID" -- bash -c "
|
||||
apt-get update && \
|
||||
apt-get install -y va-driver-all ocl-icd-libopencl1 intel-opencl-icd vainfo intel-gpu-tools && \
|
||||
chgrp video /dev/dri && chmod 755 /dev/dri && \
|
||||
adduser root video && adduser root render
|
||||
"
|
||||
msg_ok "Controladores de iGPU instalados dentro del contenedor."
|
||||
}
|
||||
|
||||
##########################################################
|
||||
|
||||
# Instalar TPU en host y verificación.
|
||||
NEED_REBOOT=0
|
||||
install_coral_host() {
|
||||
FORCE_REINSTALL=$1
|
||||
|
||||
# Verificar si el controlador ya está instalado
|
||||
if [ "$FORCE_REINSTALL" != "--force" ]; then
|
||||
msg_info "Verificando si los controladores de Coral TPU ya están instalados..."
|
||||
if dpkg -l | grep -qw gasket-dkms; then
|
||||
msg_ok "Los controladores de Coral TPU ya están instalados."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
msg_info "Instalando controladores de Coral TPU en el host..."
|
||||
verify_and_add_repos
|
||||
apt-get install -y git devscripts dh-dkms dkms pve-headers-$(uname -r)
|
||||
|
||||
# Clonar la rama predeterminada del repositorio
|
||||
cd /tmp
|
||||
rm -rf gasket-driver
|
||||
msg_info "Clonando la rama predeterminada del repositorio de Google Coral..."
|
||||
git clone https://github.com/google/gasket-driver.git
|
||||
if [ $? -ne 0 ]; then
|
||||
msg_error "No se pudo clonar el repositorio."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd gasket-driver/
|
||||
|
||||
# Construir e instalar el paquete .deb
|
||||
debuild -us -uc -tc -b
|
||||
if [ $? -ne 0 ]; then
|
||||
msg_error "Error al construir los paquetes del controlador."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dpkg -i ../gasket-dkms_*.deb
|
||||
if [ $? -ne 0 ]; then
|
||||
msg_error "Error al instalar los paquetes del controlador."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
msg_ok "Controladores de Coral TPU instalados en el host desde la rama predeterminada."
|
||||
NEED_REBOOT=1 # Marcar que se requiere reinicio completo del servidor
|
||||
}
|
||||
|
||||
|
||||
################################################
|
||||
# Instalar controladores Coral TPU en el contenedor
|
||||
install_coral_in_container() {
|
||||
msg_info "Detectando dispositivos Coral TPU dentro del contenedor..."
|
||||
CORAL_M2=$(lspci | grep -i "Global Unichip")
|
||||
|
||||
if [[ -n "$CORAL_M2" ]]; then
|
||||
DRIVER_OPTION=$(whiptail --title "Seleccionar versión de controladores" \
|
||||
--menu "Elige la versión de controladores para Coral M.2:\n\nPrecaución: El modo máximo genera más calor." 15 60 2 \
|
||||
1 "libedgetpu1-std (rendimiento estándar)" \
|
||||
2 "libedgetpu1-max (máximo rendimiento)" 3>&1 1>&2 2>&3)
|
||||
|
||||
case "$DRIVER_OPTION" in
|
||||
1) DRIVER_PACKAGE="libedgetpu1-std" ;;
|
||||
2) DRIVER_PACKAGE="libedgetpu1-max" ;;
|
||||
*) DRIVER_PACKAGE="libedgetpu1-std" ;;
|
||||
esac
|
||||
else
|
||||
DRIVER_PACKAGE="libedgetpu1-std"
|
||||
fi
|
||||
|
||||
pct start "$CONTAINER_ID"
|
||||
pct exec "$CONTAINER_ID" -- bash -c "
|
||||
apt-get update && \
|
||||
apt-get install -y gnupg python3 python3-pip python3-venv && \
|
||||
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/coral-edgetpu.gpg && \
|
||||
echo 'deb [signed-by=/usr/share/keyrings/coral-edgetpu.gpg] https://packages.cloud.google.com/apt coral-edgetpu-stable main' | tee /etc/apt/sources.list.d/coral-edgetpu.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y $DRIVER_PACKAGE
|
||||
"
|
||||
msg_ok "Controladores de Coral TPU instalados dentro del contenedor."
|
||||
}
|
||||
|
||||
# Menú principal
|
||||
main_menu() {
|
||||
OPTIONS=(
|
||||
1 "Añadir aceleración gráfica HW iGPU"
|
||||
2 "Añadir Coral TPU + HW iGPU"
|
||||
)
|
||||
|
||||
OPTION=$(whiptail --title "Menú Principal" --menu "Selecciona los recursos a añadir a un LXC:" 15 60 2 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
|
||||
case "$OPTION" in
|
||||
1)
|
||||
# Configuración solo para iGPU
|
||||
configure_lxc_for_igpu
|
||||
install_igpu_in_container
|
||||
if pct status "$CONTAINER_ID" | grep -q "running"; then
|
||||
pct restart "$CONTAINER_ID"
|
||||
else
|
||||
pct start "$CONTAINER_ID"
|
||||
fi
|
||||
msg_ok "El contenedor $CONTAINER_ID ha sido reiniciado para aplicar los cambios de iGPU."
|
||||
;;
|
||||
2)
|
||||
if dpkg -l | grep -qw gasket-dkms; then
|
||||
msg_info "Controladores de Coral ya están instalados en el host."
|
||||
|
||||
if (whiptail --title "Reinstalar controladores" --yesno "¿Quieres reinstalar los controladores de Coral en el servidor?\n(Esto solo es necesario en caso de error)" 10 60); then
|
||||
msg_info "Reinstalando los controladores de Coral en el host..."
|
||||
install_coral_host --force
|
||||
configure_lxc_for_coral && CHANGES_MADE=1
|
||||
install_coral_in_container && CHANGES_MADE=1
|
||||
configure_lxc_for_igpu && CHANGES_MADE=1
|
||||
install_igpu_in_container && CHANGES_MADE=1
|
||||
msg_info "Reiniciando el servicio udev para aplicar cambios..."
|
||||
systemctl restart udev
|
||||
msg_ok "El servicio udev ha sido reiniciado con éxito. No se requiere reinicio completo del servidor."
|
||||
else
|
||||
configure_lxc_for_coral && CHANGES_MADE=1
|
||||
install_coral_in_container && CHANGES_MADE=1
|
||||
configure_lxc_for_igpu && CHANGES_MADE=1
|
||||
install_igpu_in_container && CHANGES_MADE=1
|
||||
if [ "$CHANGES_MADE" -eq 1 ]; then
|
||||
if pct status "$CONTAINER_ID" | grep -q "running"; then
|
||||
pct restart "$CONTAINER_ID"
|
||||
else
|
||||
pct start "$CONTAINER_ID"
|
||||
fi
|
||||
msg_ok "El contenedor $CONTAINER_ID ha sido reiniciado para aplicar los cambios de Coral TPU."
|
||||
fi
|
||||
fi
|
||||
else
|
||||
msg_info "Instalando controladores de Coral por primera vez en el host..."
|
||||
install_coral_host
|
||||
configure_lxc_for_coral && CHANGES_MADE=1
|
||||
install_coral_in_container && CHANGES_MADE=1
|
||||
configure_lxc_for_igpu && CHANGES_MADE=1
|
||||
install_igpu_in_container && CHANGES_MADE=1
|
||||
if pct status "$CONTAINER_ID" | grep -q "running"; then
|
||||
pct restart "$CONTAINER_ID"
|
||||
else
|
||||
pct start "$CONTAINER_ID"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
msg_error "Opción no válida. Saliendo."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
msg_ok "Configuración completada."
|
||||
}
|
||||
|
||||
# Solicitar reinicio al final si es necesario
|
||||
final_restart_prompt() {
|
||||
if [ "$NEED_REBOOT" -eq 1 ]; then
|
||||
msg_info "Se recomienda reiniciar el servidor para aplicar los cambios correctamente."
|
||||
restart_prompt
|
||||
fi
|
||||
}
|
||||
|
||||
# Iniciar
|
||||
validate_pve_version
|
||||
select_container
|
||||
main_menu
|
||||
final_restart_prompt
|
@ -1,36 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Mensaje inicial
|
||||
whiptail --title "Reconectar discos en Proxmox" --msgbox "Este script te ayudará a reconectar los volúmenes LVM y LVM-thin en tu instalación de Proxmox recién restaurada." 12 60
|
||||
|
||||
# 1. Detectar grupos de volúmenes
|
||||
VG_LIST=$(vgscan --ignorelockingfailure --reportformat json | jq -r '.report[0].vg[].vg_name')
|
||||
|
||||
if [ -z "$VG_LIST" ]; then
|
||||
whiptail --title "Error" --msgbox "No se detectaron grupos de volúmenes LVM en el sistema." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. Seleccionar grupo de volúmenes a activar
|
||||
VG_SELECCIONADOS=$(whiptail --title "Seleccionar Grupos de Volúmenes" --checklist "Selecciona los grupos de volúmenes que deseas activar:" 20 60 10 $(for vg in $VG_LIST; do echo "$vg OFF"; done) 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$VG_SELECCIONADOS" ]; then
|
||||
whiptail --title "Error" --msgbox "No se seleccionó ningún grupo de volúmenes." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 3. Activar los grupos de volúmenes seleccionados
|
||||
for VG in $VG_SELECCIONADOS; do
|
||||
VG=$(echo "$VG" | tr -d '"') # Eliminar comillas
|
||||
vgchange -ay "$VG"
|
||||
done
|
||||
|
||||
whiptail --title "Volúmenes Activados" --msgbox "Los grupos de volúmenes seleccionados se activaron correctamente." 8 40
|
||||
|
||||
# 4. Escanear volúmenes en Proxmox
|
||||
whiptail --title "Escanear VM" --infobox "Rescaneando las imágenes de disco y volúmenes..." 8 40
|
||||
qm rescan
|
||||
|
||||
# 5. Mensaje final
|
||||
whiptail --title "Finalizado" --msgbox "Los volúmenes y las imágenes de disco fueron reconocidos y están disponibles para usar en Proxmox." 8 40
|
||||
exit 0
|
@ -1,61 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
DUMP_DIR="/var/lib/vz/dump"
|
||||
STORAGE_CFG="/etc/pve/storage.cfg"
|
||||
|
||||
# Función para comprobar y reparar después de la restauración
|
||||
reparar_storage_cfg() {
|
||||
whiptail --title "Comprobación de Almacenamientos" --msgbox "Comprobando consistencia de los volúmenes de almacenamiento..." 8 40
|
||||
|
||||
# Verificar grupos LVM
|
||||
VG_LIST=$(vgs --noheadings -o vg_name)
|
||||
while read -r LINE; do
|
||||
if [[ "$LINE" =~ vgname ]]; then
|
||||
VG_NAME=$(echo "$LINE" | awk '{print $NF}')
|
||||
if ! echo "$VG_LIST" | grep -q "$VG_NAME"; then
|
||||
echo "El volumen $VG_NAME no existe, eliminando entrada..."
|
||||
sed -i "/vgname $VG_NAME/,/nodes/d" "$STORAGE_CFG"
|
||||
fi
|
||||
fi
|
||||
done < "$STORAGE_CFG"
|
||||
|
||||
whiptail --title "Reparación Completada" --msgbox "La comprobación de consistencia ha finalizado. Se eliminaron las entradas no válidas." 8 40
|
||||
}
|
||||
|
||||
# Restaurar copia de seguridad y comprobar
|
||||
restaurar_backup() {
|
||||
BACKUP_FILE=$(whiptail --title "Seleccionar Copia de Seguridad" --menu "Selecciona la copia de seguridad a restaurar:" 15 60 8 $(ls "$DUMP_DIR"/storage.cfg_*.bak) 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$BACKUP_FILE" ]; then
|
||||
whiptail --title "Error" --msgbox "No se seleccionó ninguna copia de seguridad." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp "$BACKUP_FILE" "$STORAGE_CFG"
|
||||
whiptail --title "Restauración Completada" --msgbox "Se ha restaurado el archivo storage.cfg desde la copia de seguridad: $BACKUP_FILE" 8 40
|
||||
|
||||
reparar_storage_cfg
|
||||
}
|
||||
|
||||
# Menú principal
|
||||
OPTION=$(whiptail --title "Gestor de Storage.cfg" --menu "Selecciona una opción:" 15 60 3 \
|
||||
"1" "Realizar copia de seguridad del archivo storage.cfg" \
|
||||
"2" "Restaurar copia de seguridad y comprobar consistencia" \
|
||||
"3" "Reparar archivo storage.cfg si se han cambiado discos" 3>&1 1>&2 2>&3)
|
||||
|
||||
case $OPTION in
|
||||
1)
|
||||
BACKUP_FILE="${DUMP_DIR}/storage.cfg_$(date +%Y%m%d%H%M%S).bak"
|
||||
cp "$STORAGE_CFG" "$BACKUP_FILE"
|
||||
whiptail --title "Copia de Seguridad" --msgbox "Se ha creado una copia de seguridad en: $BACKUP_FILE" 8 40
|
||||
;;
|
||||
2)
|
||||
restaurar_backup
|
||||
;;
|
||||
3)
|
||||
reparar_storage_cfg
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user