diff --git a/scripts/ProxmoxBakupRestore.sh b/scripts/ProxmoxBakupRestore.sh deleted file mode 100644 index b727eae..0000000 --- a/scripts/ProxmoxBakupRestore.sh +++ /dev/null @@ -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 diff --git a/scripts/Storage_Management.sh b/scripts/Storage_Management.sh deleted file mode 100644 index 52e0e5f..0000000 --- a/scripts/Storage_Management.sh +++ /dev/null @@ -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 diff --git a/scripts/disk-passthrough_ct.sh b/scripts/disk-passthrough_ct.sh new file mode 100644 index 0000000..18f303d --- /dev/null +++ b/scripts/disk-passthrough_ct.sh @@ -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 \ No newline at end of file diff --git a/scripts/igpu_tpu.sh b/scripts/igpu_tpu.sh deleted file mode 100644 index 1f461ba..0000000 --- a/scripts/igpu_tpu.sh +++ /dev/null @@ -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 diff --git a/scripts/reconnect-lvm.sh b/scripts/reconnect-lvm.sh deleted file mode 100644 index 0c258f3..0000000 --- a/scripts/reconnect-lvm.sh +++ /dev/null @@ -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 diff --git a/scripts/storage-manager.sh b/scripts/storage-manager.sh deleted file mode 100644 index bd93d25..0000000 --- a/scripts/storage-manager.sh +++ /dev/null @@ -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 diff --git a/scripts/vm/syno_test.sh b/scripts/vm/syno_test.sh deleted file mode 100644 index 42e15f4..0000000 --- a/scripts/vm/syno_test.sh +++ /dev/null @@ -1,1084 +0,0 @@ -#!/usr/bin/env bash - -# ========================================================== -# Synology VM Creator for ProxMenuX version TEST -# ========================================================== -# Author : MacRimi -# Copyright : (c) 2024 MacRimi -# License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE) -# Version : 1.0 -# Last Updated: 13/03/2025 -# ========================================================== -# This script creates a Synology DSM virtual machine in Proxmox -# ========================================================== - -# Configuration -REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main" -UTILS_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main/scripts/utils.sh" - - -# Source utils.sh for common functions and styles -if ! source <(curl -sSf "$UTILS_URL"); then - echo "Error: Could not load utils.sh from $UTILS_URL" - exit 1 -fi -# ========================================================== - -GEN_MAC="02" -for i in {1..5}; do - BYTE=$(printf "%02X" $((RANDOM % 256))) - GEN_MAC="${GEN_MAC}:${BYTE}" -done - -NEXTID=$(pvesh get /cluster/nextid 2>/dev/null || echo "100") -NAME="Synology VM" -IMAGES_DIR="/var/lib/vz/template/iso" -ERROR_FLAG=false - - - - - -function exit_script() { - clear - if whiptail --backtitle "ProxMenuX" --title "$NAME" --yesno "This will create a New $NAME. Proceed?" 10 58; then - start_script - else - clear - exit - fi -} - - -# Definir función header_info al inicio del script - -function header_info() { - clear - show_proxmenux_logo - echo -e "${BL}╔═══════════════════════════════════════════════╗${CL}" - echo -e "${BL}║ ║${CL}" - echo -e "${BL}║${YWB} Synology VM Creator ${BL}║${CL}" - echo -e "${BL}║ ║${CL}" - echo -e "${BL}╚═══════════════════════════════════════════════╝${CL}" - echo -e -} -# ========================================================== - - - - - - -# ========================================================== -# start Script -# ========================================================== -function start_script() { - if (whiptail --backtitle "ProxMenuX" --title "SETTINGS" --yesno "Use Default Settings?" --no-button Advanced 10 58); then - header_info - echo -e "${DEF}Using Default Settings${CL}" - default_settings - else - header_info - echo -e "${CUS}Using Advanced Settings${CL}" - advanced_settings - fi -} -# ========================================================== - - - - -# ========================================================== -# Default Settings -# ========================================================== -function default_settings() { - VMID="$NEXTID" - FORMAT="" - MACHINE=" -machine q35" - BIOS_TYPE=" -bios ovmf" - DISK_CACHE="" - HN="Synology-DSM" - CPU_TYPE=" -cpu host" - CORE_COUNT="2" - RAM_SIZE="4096" - BRG="vmbr0" - MAC="$GEN_MAC" - VLAN="" - MTU="" - SERIAL_PORT="socket" - START_VM="no" - - echo -e "${DGN}Using Virtual Machine ID: ${BGN}${VMID}${CL}" - echo -e "${DGN}Using Machine Type: ${BGN}q35${CL}" - echo -e "${DGN}Using BIOS Type: ${BGN}OVMF (UEFI)${CL}" - echo -e "${DGN}Using Hostname: ${BGN}${HN}${CL}" - echo -e "${DGN}Using CPU Model: ${BGN}Host${CL}" - echo -e "${DGN}Allocated Cores: ${BGN}${CORE_COUNT}${CL}" - echo -e "${DGN}Allocated RAM: ${BGN}${RAM_SIZE}${CL}" - echo -e "${DGN}Using Bridge: ${BGN}${BRG}${CL}" - echo -e "${DGN}Using MAC Address: ${BGN}${MAC}${CL}" - echo -e "${DGN}Using VLAN: ${BGN}Default${CL}" - echo -e "${DGN}Using Interface MTU Size: ${BGN}Default${CL}" - echo -e "${DGN}Configuring Serial Port: ${BGN}${SERIAL_PORT}${CL}" - echo -e "${DGN}Start VM when completed: ${BGN}${START_VM}${CL}" - echo -e - echo -e "${DEF}Creating a $NAME using the above default settings${CL}" - - sleep 1 - select_disk_type -} -# ========================================================== - - - - - -# ========================================================== -# advanced Settings -# ========================================================== -function advanced_settings() { - # VM ID Selection - while true; do - if VMID=$(whiptail --backtitle "ProxMenuX" --inputbox "Set Virtual Machine ID" 8 58 $NEXTID --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then - if [ -z "$VMID" ]; then - VMID="$NEXTID" - fi - if pct status "$VMID" &>/dev/null || qm status "$VMID" &>/dev/null; then - echo -e "${CROSS}${RD} ID $VMID is already in use${CL}" - sleep 1 - continue - fi - echo -e "${DGN}Virtual Machine ID: ${BGN}$VMID${CL}" - break - else - exit_script - fi - done - - # Machine Type Selection - if MACH=$(whiptail --backtitle "ProxMenuX" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \ - "q35" "Machine q35" ON \ - "i440fx" "Machine i440fx" OFF \ - 3>&1 1>&2 2>&3); then - if [ $MACH = q35 ]; then - echo -e "${DGN}Using Machine Type: ${BGN}$MACH${CL}" - FORMAT="" - MACHINE=" -machine q35" - else - echo -e "${DGN}Using Machine Type: ${BGN}$MACH${CL}" - FORMAT=",efitype=4m" - MACHINE="" - fi - else - exit_script - fi - - # BIOS Type Selection - if BIOS=$(whiptail --backtitle "ProxMenuX" --title "BIOS TYPE" --radiolist --cancel-button Exit-Script "Choose BIOS Type" 10 58 2 \ - "ovmf" "UEFI (OVMF)" ON \ - "seabios" "SeaBIOS (Legacy)" OFF \ - 3>&1 1>&2 2>&3); then - if [ "$BIOS" = "seabios" ]; then - echo -e "${DGN}Using BIOS Type: ${BGN}SeaBIOS${CL}" - BIOS_TYPE=" -bios seabios" - else - echo -e "${DGN}Using BIOS Type: ${BGN}OVMF (UEFI)${CL}" - BIOS_TYPE=" -bios ovmf" - fi - else - exit_script - fi - - # Hostname Selection - if VM_NAME=$(whiptail --backtitle "ProxMenuX" --inputbox "Set Hostname" 8 58 Synology-DSM --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then - if [ -z $VM_NAME ]; then - HN="Synology-DSM" - echo -e "${DGN}Using Hostname: ${BGN}$HN${CL}" - else - HN=$(echo ${VM_NAME,,} | tr -d ' ') - echo -e "${DGN}Using Hostname: ${BGN}$HN${CL}" - fi - else - exit_script - fi - - # CPU Type Selection - if CPU_TYPE1=$(whiptail --backtitle "ProxMenuX" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \ - "1" "Host" ON \ - "0" "KVM64" OFF \ - 3>&1 1>&2 2>&3); then - if [ $CPU_TYPE1 = "1" ]; then - echo -e "${DGN}Using CPU Model: ${BGN}Host${CL}" - CPU_TYPE=" -cpu host" - else - echo -e "${DGN}Using CPU Model: ${BGN}KVM64${CL}" - CPU_TYPE="" - fi - else - exit_script - fi - - # Core Count Selection - if CORE_COUNT=$(whiptail --backtitle "ProxMenuX" --inputbox "Allocate CPU Cores" 8 58 2 --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then - if [ -z $CORE_COUNT ]; then - CORE_COUNT="2" - echo -e "${DGN}Allocated Cores: ${BGN}$CORE_COUNT${CL}" - else - echo -e "${DGN}Allocated Cores: ${BGN}$CORE_COUNT${CL}" - fi - else - exit_script - fi - - # RAM Size Selection - if RAM_SIZE=$(whiptail --backtitle "ProxMenuX" --inputbox "Allocate RAM in MiB" 8 58 4096 --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then - if [ -z $RAM_SIZE ]; then - RAM_SIZE="4096" - echo -e "${DGN}Allocated RAM: ${BGN}$RAM_SIZE${CL}" - else - echo -e "${DGN}Allocated RAM: ${BGN}$RAM_SIZE${CL}" - fi - else - exit_script - fi - - # Bridge Selection - if BRG=$(whiptail --backtitle "ProxMenuX" --inputbox "Set a Bridge" 8 58 vmbr0 --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then - if [ -z $BRG ]; then - BRG="vmbr0" - echo -e "${DGN}Using Bridge: ${BGN}$BRG${CL}" - else - echo -e "${DGN}Using Bridge: ${BGN}$BRG${CL}" - fi - else - exit_script - fi - - # MAC Address Selection - if MAC1=$(whiptail --backtitle "ProxMenuX" --inputbox "Set a MAC Address" 8 58 $GEN_MAC --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then - if [ -z $MAC1 ]; then - MAC="$GEN_MAC" - echo -e "${DGN}Using MAC Address: ${BGN}$MAC${CL}" - else - MAC="$MAC1" - echo -e "${DGN}Using MAC Address: ${BGN}$MAC1${CL}" - fi - else - exit_script - fi - - # VLAN Selection - if VLAN1=$(whiptail --backtitle "ProxMenuX" --inputbox "Set a Vlan(leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then - if [ -z $VLAN1 ]; then - VLAN1="Default" - VLAN="" - echo -e "${DGN}Using Vlan: ${BGN}$VLAN1${CL}" - else - VLAN=",tag=$VLAN1" - echo -e "${DGN}Using Vlan: ${BGN}$VLAN1${CL}" - fi - else - exit_script - fi - - # MTU Selection - if MTU1=$(whiptail --backtitle "ProxMenuX" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then - if [ -z $MTU1 ]; then - MTU1="Default" - MTU="" - echo -e "${DGN}Using Interface MTU Size: ${BGN}$MTU1${CL}" - else - MTU=",mtu=$MTU1" - echo -e "${DGN}Using Interface MTU Size: ${BGN}$MTU1${CL}" - fi - else - exit_script - fi - - - - # Confirmation - if (whiptail --backtitle "ProxMenuX" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create a $NAME?" --no-button Do-Over 10 58); then - echo -e - echo -e "${CUS}Creating a $NAME using the above advanced settings${CL}" - - # Ahora preguntamos por el tipo de disco - sleep 1 - select_disk_type - else - header_info - sleep 1 - echo -e "${CUS}Using Advanced Settings${CL}" - advanced_settings - fi -} -# ========================================================== - - - - - -# ========================================================== -# Select Disk -# ========================================================== -function select_disk_type() { - - DISK_TYPE=$(whiptail --backtitle "ProxMenuX" --title "DISK TYPE" --menu "Choose disk type:" 12 58 2 \ - "virtual" "Create virtual disk" \ - "passthrough" "Use physical disk passthrough" \ - --ok-button "Select" --cancel-button "Cancel" 3>&1 1>&2 2>&3) - - EXIT_STATUS=$? - - if [[ $EXIT_STATUS -ne 0 ]]; then - clear - header_info - msg_error "Operation cancelled by user. Returning to start scrip..." - sleep 2 - if whiptail --backtitle "ProxMenuX" --title "$NAME" --yesno "This will create a New $NAME. Proceed?" 10 58; then - start_script - else - clear - exit - fi - fi - - if [[ "$DISK_TYPE" == "virtual" ]]; then - select_virtual_disk - else - select_passthrough_disk - fi -} - -# ========================================================== - - - - - -# ========================================================== -# Select Virtual Disks -# ========================================================== -function select_virtual_disk() { - - - # Inicializar variables - VIRTUAL_DISKS=() - - # Bucle para añadir múltiples discos - local add_more_disks=true - while $add_more_disks; do - - msg_info "Detecting available storage volumes..." - - # Obtener lista de almacenamiento disponible - STORAGE_MENU=() - while read -r line; do - TAG=$(echo $line | awk '{print $1}') - TYPE=$(echo $line | awk '{print $2}') - FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format "%.2f" | awk '{printf( "%9sB", $6)}') - ITEM=$(printf "%-15s %-10s %-15s" "$TAG" "$TYPE" "$FREE") - STORAGE_MENU+=("$TAG" "$ITEM" "OFF") - done < <(pvesm status -content images | awk 'NR>1') - - # Comprobar que hay almacenamiento disponible - VALID=$(pvesm status -content images | awk 'NR>1') - if [ -z "$VALID" ]; then - msg_error "Unable to detect a valid storage location." - sleep 2 - select_disk_type - fi - - - # Seleccionar almacenamiento - if [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then - STORAGE=${STORAGE_MENU[0]} - msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location." - else - - kill $SPINNER_PID > /dev/null - STORAGE=$(whiptail --backtitle "ProxMenuX" --title "Select Storage Volume" --radiolist \ - "Choose the storage volume for the virtual disk:\n" 20 78 10 \ - "${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3) - - if [ $? -ne 0 ] || [ -z "$STORAGE" ]; then - if [ ${#VIRTUAL_DISKS[@]} -eq 0 ]; then - msg_error "No storage selected. At least one disk is required." - select_disk_type - else - # Si ya hay discos añadidos, continuar con el script - add_more_disks=false - continue - fi - fi - - - fi - - # Solicitar tamaño del disco - DISK_SIZE=$(whiptail --backtitle "ProxMenuX" --inputbox "System Disk Size (GB)" 8 58 32 --title "VIRTUAL DISK" --cancel-button Cancel 3>&1 1>&2 2>&3) - - if [ $? -ne 0 ]; then - if [ ${#VIRTUAL_DISKS[@]} -eq 0 ]; then - msg_error "Disk size not specified. At least one disk is required." - sleep 2 - select_disk_type - - else - # Si ya hay discos añadidos, continuar con el script - add_more_disks=false - continue - fi - fi - - if [ -z "$DISK_SIZE" ]; then - DISK_SIZE="32" - fi - - # Almacenar la configuración en la lista de discos - VIRTUAL_DISKS+=("${STORAGE}:${DISK_SIZE}") - - - # Preguntar si desea crear otro disco - if ! whiptail --backtitle "ProxMenuX" --title "Add Another Disk" \ - --yesno "Do you want to add another virtual disk?" 8 58; then - add_more_disks=false - fi - done - - # Mostrar resumen de los discos creados - if [ ${#VIRTUAL_DISKS[@]} -gt 0 ]; then - - msg_ok "Virtual Disks Created:" - for i in "${!VIRTUAL_DISKS[@]}"; do - echo -e "${TAB}${BL}- Disk $((i+1)): ${VIRTUAL_DISKS[$i]}GB${CL}" - done - fi - - - export VIRTUAL_DISKS - - - select_loader -} - -# ========================================================== - - - - - - -# ========================================================== -# Select Physical Disks -# ========================================================== -function select_passthrough_disk() { - - - FREE_DISKS=() - - # Obtener la lista de discos montados - USED_DISKS=$(lsblk -n -o PKNAME,TYPE | grep 'lvm' | awk '{print "/dev/" $1}') - MOUNTED_DISKS=$(mount | grep -o '/dev/[a-z]*' | sort | uniq) - - # Obtener todos los discos físicos - while read -r DISK; do - - if ! echo "$USED_DISKS" | grep -q "$DISK" && ! echo "$MOUNTED_DISKS" | grep -q "$DISK"; then - - MODEL=$(lsblk -dn -o MODEL "$DISK" | xargs) - SIZE=$(lsblk -dn -o SIZE "$DISK" | xargs) - DESCRIPTION=$(printf "%-40s %10s" "$MODEL" "$SIZE") - FREE_DISKS+=("$DISK" "$DESCRIPTION" "OFF") - fi - done < <(lsblk -dn -e 7,11 -o PATH) - - - # Handle no available disks - if [ "${#FREE_DISKS[@]}" -eq 0 ]; then - whiptail --title "Error" --msgbox "No disks available for this VM." 8 40 - select_disk_type - fi - - # Calculate maximum content length - MAX_WIDTH=$(printf "%s\n" "${FREE_DISKS[@]}" | awk '{print length}' | sort -nr | head -n1) - TOTAL_WIDTH=$((MAX_WIDTH + 20)) # Add additional margin - - # Set a reasonable minimum width - if [ $TOTAL_WIDTH -lt 70 ]; then - TOTAL_WIDTH=70 - fi - - # Display menu to select multiple free disks with dynamically calculated width - SELECTED_DISKS=$(whiptail --title "Select Disks" --checklist \ - "Select the disks you want to use (use spacebar to select):" 20 $TOTAL_WIDTH 10 \ - "${FREE_DISKS[@]}" 3>&1 1>&2 2>&3) - - # Check if at least one disk was selected - if [ -z "$SELECTED_DISKS" ]; then - msg_error "Disk not specified. At least one disk is required." - sleep 2 - select_disk_type - fi - - # Process selected disks - msg_ok "Disk passthrough selected:" - PASSTHROUGH_DISKS=() - for DISK in $(echo "$SELECTED_DISKS" | tr -d '"'); do - DISK_INFO=$(lsblk -ndo MODEL,SIZE "$DISK" | xargs) - echo -e "${TAB}${CL}${BL}- $DISK $DISK_INFO${GN}${CL}" - PASSTHROUGH_DISKS+=("$DISK") - done - - - select_loader -} -# ========================================================== - - - - - - -# ========================================================== -# Select Loader -# ========================================================== -function select_loader() { - # Ensure the images directory exists - if [ ! -d "$IMAGES_DIR" ]; then - msg_info "Creating images directory" - mkdir -p "$IMAGES_DIR" - chmod 755 "$IMAGES_DIR" - msg_ok "Images directory created: $IMAGES_DIR" - fi - - # Create the loader selection menu - LOADER_OPTION=$(whiptail --backtitle "ProxMenuX" --title "SELECT LOADER" --menu "Choose a loader for Synology DSM:" 15 70 4 \ - "1" "AuxXxilium Arc Loader" \ - "2" "RedPill Loader (RROrg - rr)" \ - "3" "TinyCore RedPill Loader (PeterSuh-Q3 M-shell)" \ - "4" "Custom Loader Image (from $IMAGES_DIR)" \ - 3>&1 1>&2 2>&3) - - if [ -z "$LOADER_OPTION" ]; then - exit_script - fi - - case $LOADER_OPTION in - 1) - LOADER_TYPE="arc" - LOADER_NAME="AuxXxilium Arc" - LOADER_URL="https://github.com/AuxXxilium/arc/releases/latest" - echo -e "${DGN}${TAB}Selected Loader: ${BGN}$LOADER_NAME${CL}" - download_loader - ;; - 2) - LOADER_TYPE="redpill" - LOADER_NAME="RedPill rr" - LOADER_URL="https://github.com/RROrg/rr/releases/latest" - echo -e "${DGN}${TAB}Selected Loader: ${BGN}$LOADER_NAME${CL}" - download_loader - ;; - 3) - LOADER_TYPE="tinycore" - LOADER_NAME="TinyCore RedPill M-shell" - LOADER_URL="https://github.com/PeterSuh-Q3/tinycore-redpill/releases/latest" - echo -e "${DGN}${TAB}Selected Loader: ${BGN}$LOADER_NAME${CL}" - download_loader - ;; - 4) - LOADER_TYPE="custom" - LOADER_NAME="Custom Image" - echo -e "${DGN}${TAB}Selected Loader: ${BGN}$LOADER_NAME${CL}" - select_custom_image - ;; - esac -} - -function select_custom_image() { - # Check if there are any images in the directory - IMAGES=$(find "$IMAGES_DIR" -type f -name "*.img" -o -name "*.iso" -o -name "*.qcow2" -o -name "*.vmdk" | sort) - - if [ -z "$IMAGES" ]; then - whiptail --title "No Images Found" --msgbox "No compatible images found in $IMAGES_DIR\n\nSupported formats: .img, .iso, .qcow2, .vmdk\n\nPlease add some images and try again." 15 70 - select_loader - fi - - # Create an array of image options for whiptail - IMAGE_OPTIONS=() - - while read -r img; do - filename=$(basename "$img") - filesize=$(du -h "$img" | cut -f1) - IMAGE_OPTIONS+=("$img" "$filesize") - done <<< "$IMAGES" - - # Let the user select an image - LOADER_FILE=$(whiptail --backtitle "ProxMenuX" --title "SELECT CUSTOM IMAGE" --menu "Choose a custom image:" 20 70 10 "${IMAGE_OPTIONS[@]}" 3>&1 1>&2 2>&3) - - if [ -z "$LOADER_FILE" ]; then - msg_error "No custom image selected" - exit_script - fi - - echo -e "${DGN}${TAB}Using Custom Image: ${BGN}$(basename "$LOADER_FILE")${CL}" - FILE=$(basename "$LOADER_FILE") -} -# ========================================================== - - - - - - - -# ========================================================== -# Download Loader -# ========================================================== -function download_loader() { - - echo -e "${DGN}${TAB}Retrieving the URL for the ${BGN}$LOADER_NAME loader${CL}" - - case $LOADER_TYPE in - arc) - curl -s https://api.github.com/repos/AuxXxilium/arc/releases/latest \ - | grep "browser_download_url.*evo.img.zip" \ - | cut -d '"' -f 4 \ - | xargs wget -q --show-progress -O "$IMAGES_DIR/evo.img.zip" - - if [ -f "$IMAGES_DIR/evo.img.zip" ]; then - cd "$IMAGES_DIR" - unzip -q evo.img.zip - rm evo.img.zip - FILE="arc.img" - LOADER_FILE="$IMAGES_DIR/$FILE" - cd - > /dev/null - else - msg_error "Failed to download $LOADER_NAME loader" - sleep 1 - select_loader - fi - ;; - - redpill) - curl -s https://api.github.com/repos/RROrg/rr/releases/latest \ - | grep "browser_download_url.*\.img\.zip" \ - | cut -d '"' -f 4 \ - | xargs wget -q --show-progress -O "$IMAGES_DIR/rr.img.zip" - - if [ -f "$IMAGES_DIR/rr.img.zip" ]; then - cd "$IMAGES_DIR" - msg_info "Unzipping $LOADER_NAME loader. Please wait..." - unzip -qo rr.img.zip - msg_ok "Unzipped $LOADER_NAME loader successfully." - rm -f rr.img.zip - FILE="rr.img" - LOADER_FILE="$IMAGES_DIR/$FILE" - cd - > /dev/null - fi - - ;; - - tinycore) - curl -s https://api.github.com/repos/PeterSuh-Q3/tinycore-redpill/releases/latest \ - | grep "browser_download_url.*tinycore-redpill.v.*img.gz" \ - | cut -d '"' -f 4 \ - | xargs wget -q --show-progress -O "$IMAGES_DIR/tinycore.img.gz" - - if [ -f "$IMAGES_DIR/tinycore.img.gz" ]; then - cd "$IMAGES_DIR" - - msg_info "Unzipping $LOADER_NAME loader. Please wait..." - gunzip -f tinycore.img.gz 2> /dev/null - msg_ok "Unzipped $LOADER_NAME loader successfully." - FILE="tinycore.img" - LOADER_FILE="$IMAGES_DIR/$FILE" - cd - > /dev/null - - else - msg_error "Failed to download $LOADER_NAME loader" - sleep 1 - select_loader - - fi - ;; - esac - - msg_ok "Downloaded ${CL}${BL}${FILE}${CL} to ${IMAGES_DIR}" -} -# ======================================================= - - - - - -# ========================================================== -# Select UEFI Storage -# ========================================================== -function select_efi_storage() { - local vmid=$1 - local STORAGE="" - - STORAGE_MENU=() - - while read -r line; do - TAG=$(echo $line | awk '{print $1}') - TYPE=$(echo $line | awk '{printf "%-10s", $2}') - FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format "%.2f" | awk '{printf( "%9sB", $6)}') - - # Crear la línea del menú - ITEM=" Type: $TYPE Free: $FREE" - OFFSET=2 - if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then - MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET)) - fi - - STORAGE_MENU+=("$TAG" "$ITEM" "OFF") - done < <(pvesm status -content images | awk 'NR>1') - - VALID=$(pvesm status -content images | awk 'NR>1') - if [ -z "$VALID" ]; then - msg_error "Unable to detect a valid storage location for EFI disk." - - elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then - # Si hay solo una opción, usarla directamente - STORAGE=${STORAGE_MENU[0]} - - else - # Mostrar menú radiolist para seleccionar el volumen - kill $SPINNER_PID > /dev/null - while [ -z "${STORAGE:+x}" ]; do - STORAGE=$(whiptail --backtitle "ProxMenuX" --title "EFI Disk Storage" --radiolist \ - "Choose the storage volume for the EFI disk (4MB):\n\nUse Spacebar to select." \ - 16 $(($MSG_MAX_LENGTH + 23)) 6 \ - "${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3) || exit - - done - - fi - - echo "$STORAGE" -} -# ========================================================== - - - - - -# ========================================================== -# Select Storage Loader -# ========================================================== -function select_storage_volume() { - local vmid=$1 - local purpose=$2 - local STORAGE="" - - STORAGE_MENU=() - - while read -r line; do - TAG=$(echo $line | awk '{print $1}') - TYPE=$(echo $line | awk '{printf "%-10s", $2}') - FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format "%.2f" | awk '{printf( "%9sB", $6)}') - - # Crear la línea del menú - ITEM=" Type: $TYPE Free: $FREE" - OFFSET=2 - if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then - MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET)) - fi - - STORAGE_MENU+=("$TAG" "$ITEM" "OFF") - done < <(pvesm status -content images | awk 'NR>1') - - VALID=$(pvesm status -content images | awk 'NR>1') - if [ -z "$VALID" ]; then - msg_error "Unable to detect a valid storage location." - exit 1 - elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then - # Si hay solo una opción, usarla directamente - STORAGE=${STORAGE_MENU[0]} - else - # Mostrar menú radiolist para seleccionar el volumen - while [ -z "${STORAGE:+x}" ]; do - STORAGE=$(whiptail --backtitle "ProxMenuX" --title "Storage Pools" --radiolist \ - "Choose the storage volume for $purpose:\n\nUse Spacebar to select." \ - 16 $(($MSG_MAX_LENGTH + 23)) 6 \ - "${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3) || exit - done - fi - - echo "$STORAGE" -} - - - - - - -# ========================================================== -# Create VM -# ========================================================== -function create_vm() { - - # Create the VM - qm create $VMID -agent 1${MACHINE} -tablet 0 -localtime 1${BIOS_TYPE}${CPU_TYPE} -cores $CORE_COUNT -memory $RAM_SIZE \ - -name $HN -tags proxmenux -net0 virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU -onboot 1 -ostype l26 -scsihw virtio-scsi-pci \ - -serial0 socket - msg_ok "Create a $NAME" - - - -# Verificar si se está usando UEFI (OVMF) =================== - if [[ "$BIOS_TYPE" == *"ovmf"* ]]; then - - msg_info "Configuring EFI disk" - EFI_STORAGE=$(select_efi_storage $VMID) - EFI_DISK_NAME="vm-${VMID}-disk-efivars" - - # Determinar tipo de almacenamiento y extensión - STORAGE_TYPE=$(pvesm status -storage $EFI_STORAGE | awk 'NR>1 {print $2}') - case $STORAGE_TYPE in - nfs | dir) - EFI_DISK_EXT=".raw" - EFI_DISK_REF="$VMID/" - ;; - *) - EFI_DISK_EXT="" - EFI_DISK_REF="" - ;; - esac - - # Crear disco EFI - if pvesm alloc "$EFI_STORAGE" "$VMID" "$EFI_DISK_NAME$EFI_DISK_EXT" 4M >/dev/null 2>&1; then - # Configurar disco EFI sin preinstalar llaves - if qm set "$VMID" -efidisk0 "$EFI_STORAGE:${EFI_DISK_REF}$EFI_DISK_NAME$EFI_DISK_EXT,pre-enrolled-keys=0" >/dev/null 2>&1; then - msg_ok "EFI disk created and configured on ${CL}${BL}$EFI_STORAGE${GN}${CL}" - else - msg_error "Failed to configure EFI disk" - ERROR_FLAG=true - fi - else - msg_error "Failed to create EFI disk" - ERROR_FLAG=true - fi - - fi -# ========================================================== - - -# Select storage volume for loader ======================= - - LOADER_STORAGE=$(select_storage_volume $VMID "loader disk") - - - # Ejecutar el comando en segundo plano y capturar su PID - qm importdisk $VMID ${LOADER_FILE} $LOADER_STORAGE > /tmp/import_log_$VMID.txt 2>&1 & - import_pid=$! - - # Mostrar un indicador simple de progreso - echo -n "Importing loader disk: " - while kill -0 $import_pid 2>/dev/null; do - echo -n "." - sleep 2.5 - done - - # Esperar a que termine el proceso - wait $import_pid - # Limpiar - rm -f /tmp/import_log_$VMID.txt - - - # Obtener el disco importado - IMPORTED_DISK=$(qm config $VMID | grep -E 'unused[0-9]+' | tail -1 | cut -d: -f1) - - # Si el disco no se importó correctamente, mostrar mensaje de error, pero continuar - if [ -z "$IMPORTED_DISK" ]; then - msg_error "Loader import failed. No disk detected." - ERROR_FLAG=true - else - msg_ok "Loader imported successfully to ${CL}${BL}$LOADER_STORAGE${GN}${CL}" - fi - - # Configure the loader disk as scsi0 - DISK_NAME="vm-${VMID}-disk-0" - # result=$(qm set "$VMID" -scsi0 "${LOADER_STORAGE}:${DISK_NAME}" 2>&1 > /dev/null) - result=$(qm set "$VMID" -ide0 "${LOADER_STORAGE}:${DISK_NAME}" 2>&1 > /dev/null) - if [[ $? -eq 0 ]]; then - # msg_ok "Configured loader disk as scsi0" - msg_ok "Configured loader disk as ide0" - else - ERROR_FLAG=true - fi - - # Set boot order to scsi0 - # result=$(qm set "$VMID" -boot order=scsi0 2>&1) - result=$(qm set "$VMID" -boot order=ide0 2>&1) - if [[ $? -eq 0 ]]; then - msg_ok "Loader configured as boot device." - else - ERROR_FLAG=true - fi - -# ========================================================== - -if [ "$DISK_TYPE" = "virtual" ]; then - # Comprobar que hay discos virtuales configurados - if [ ${#VIRTUAL_DISKS[@]} -eq 0 ]; then - msg_error "No virtual disks configured." - exit_script - fi - - DISK_INFO="" - CONSOLE_DISK_INFO="" - - for i in "${!VIRTUAL_DISKS[@]}"; do - # Extraer almacenamiento y tamaño - IFS=':' read -r STORAGE SIZE <<< "${VIRTUAL_DISKS[$i]}" - - # Determinar tipo de almacenamiento y extensión - STORAGE_TYPE=$(pvesm status -storage $STORAGE | awk 'NR>1 {print $2}') - case $STORAGE_TYPE in - nfs | dir) - DISK_EXT=".raw" - DISK_REF="$VMID/" - ;; - *) - DISK_EXT="" - DISK_REF="" - ;; - esac - - - DISK_NUM=$((i+1)) - DISK_NAME="vm-${VMID}-disk-${DISK_NUM}${DISK_EXT}" - - - # Crear disco virtual - msg_info "Creating virtual disk..." - if ! pvesm alloc "$STORAGE" "$VMID" "$DISK_NAME" "$SIZE"G >/dev/null 2>&1; then - msg_error "Failed to allocate virtual disk $DISK_NUM" - cleanup_vmid - - fi - - # Configurar disco en la VM (sata0, sata1, etc.) - SATA_ID="sata$i" - if ! qm set "$VMID" -$SATA_ID "$STORAGE:${DISK_REF}$DISK_NAME" >/dev/null 2>&1; then - msg_error "Failed to configure virtual disk as $SATA_ID" - cleanup_vmid - - fi - msg_ok "Configured virtual disk as $SATA_ID, ${SIZE}GB on ${CL}${BL}$STORAGE${CL} ${GN}" - - # Añadir información a la descripción - DISK_INFO="${DISK_INFO}

Virtual Disk $DISK_NUM: ${SIZE}GB on ${STORAGE}

" - CONSOLE_DISK_INFO="${CONSOLE_DISK_INFO}- Virtual Disk $DISK_NUM: ${SIZE}GB on ${STORAGE} ($SATA_ID)\n" - done - - - - # Preparar descripción HTML - HTML_DESC="
-

Synology DSM Virtual Machine

-

Created with ProxMenuX

-

Loader: $LOADER_NAME

- ${DISK_INFO} -
" - - # Configurar descripción - msg_info "Setting VM description" - if ! qm set "$VMID" -description "$HTML_DESC" >/dev/null 2>&1; then - msg_error "Failed to set VM description" - exit_script - fi - msg_ok "Configured VM description" - - -else - - - # Configurar múltiples discos passthrough - DISK_INFO="" - CONSOLE_DISK_INFO="" - - for i in "${!PASSTHROUGH_DISKS[@]}"; do - DISK="${PASSTHROUGH_DISKS[$i]}" - DISK_MODEL=$(lsblk -ndo MODEL "$DISK" | xargs) - DISK_SIZE=$(lsblk -ndo SIZE "$DISK" | xargs) - DISK_ID="sata$i" - - - # Configurar disco passthrough - result=$(qm set $VMID -${DISK_ID} ${DISK} 2>&1) - if [[ $? -eq 0 ]]; then - msg_ok "Configured disk ${CL}${BL}($DISK_MODEL $DISK_SIZE)${CL}${GN} as $DISK_ID" - fi - - # Añadir información del disco para la descripción HTML - DISK_INFO="${DISK_INFO}

Passthrough Disk $((i+1)): $DISK ($DISK_MODEL $DISK_SIZE)

" - - # Añadir información del disco para la consola - CONSOLE_DISK_INFO="${CONSOLE_DISK_INFO}- Passthrough Disk $((i+1)): $DISK ($DISK_MODEL $DISK_SIZE) (${DISK_ID})\n" - done - - - # Preparar descripción HTML - HTML_DESC="
-

Synology DSM Virtual Machine

-

Created with ProxMenuX

-

Loader: $LOADER_NAME

- ${DISK_INFO} -
" - - # Configurar descripción - result=$(qm set $VMID -description "$HTML_DESC" 2>&1) - if [[ $? -eq 0 ]]; then - msg_ok "Configured VM description" - fi - - -fi - - -if [ "$ERROR_FLAG" = true ]; then - msg_error "VM created with errors. Check configuration." -else - msg_success "Completed Successfully!" - - echo -e "\n${TAB}${GN}Next Steps:${CL}" - echo -e "${TAB}1. Start the VM" - echo -e "${TAB}2. Open the VM console and wait for the loader to boot" - echo -e "${TAB}3. In the loader interface, follow the instructions to select your Synology model" - echo -e "${TAB}4. Complete the DSM installation wizard" - echo -e "${TAB}5. Find your device using: https://finds.synology.com" - echo -e -fi - -} - -# ========================================================== - - - - - - -# ========================================================== -# Main execution -# ========================================================== -header_info -echo -e "\n Loading..." -sleep 1 - -# Start script -if whiptail --backtitle "ProxMenuX" --title "$NAME" --yesno "This will create a New $NAME. Proceed?" 10 58; then - start_script -else - clear - exit -fi - -# Create VM -create_vm - -# ========================================================== \ No newline at end of file