diff --git a/lxc_manager.sh b/lxc_manager.sh index 1c914c4..1fafe9a 100644 --- a/lxc_manager.sh +++ b/lxc_manager.sh @@ -2,16 +2,62 @@ ############################################# # Script de Gestion LXC pour Proxmox VE -# Date: 16/12/2025 +# Date: 18/12/2025 # Description: Gestion complète des conteneurs LXC ############################################# +# Sécurité stricte +set -euo pipefail + # Couleurs pour l'affichage -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly BLUE='\033[0;34m' +readonly NC='\033[0m' # No Color + +# Fonction pour gérer les erreurs +error_exit() { + echo -e "${RED}Erreur: $1${NC}" >&2 + read -p "Appuyez sur Entrée pour continuer..." + return 1 +} + +# Fonction pour valider un VMID +validate_vmid() { + local vmid="$1" + if [[ ! "$vmid" =~ ^[1-9][0-9]{2,8}$ ]]; then + return 1 + fi + return 0 +} + +# Fonction pour valider un nom d'hôte +validate_hostname() { + local hostname="$1" + if [[ ! "$hostname" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$ ]]; then + return 1 + fi + return 0 +} + +# Fonction pour valider une adresse IP +validate_ip() { + local ip="$1" + if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then + return 1 + fi + return 0 +} + +# Fonction pour valider un nombre positif +validate_positive_number() { + local num="$1" + if [[ ! "$num" =~ ^[1-9][0-9]*$ ]]; then + return 1 + fi + return 0 +} # Fonction pour afficher le logo show_logo() { @@ -19,7 +65,7 @@ show_logo() { echo -e "${BLUE}" echo "╔═══════════════════════════════════════════════╗" echo "║ GESTIONNAIRE LXC PROXMOX VE ║" - echo "║ Version 1.0 ║" + echo "║ Version 2.0 - Sécurisé ║" echo "╚═══════════════════════════════════════════════╝" echo -e "${NC}" } @@ -30,6 +76,11 @@ check_proxmox() { echo -e "${RED}Erreur: Ce script doit être exécuté sur un serveur Proxmox VE${NC}" exit 1 fi + + if [[ $EUID -ne 0 ]]; then + echo -e "${RED}Erreur: Ce script doit être exécuté en tant que root${NC}" + exit 1 + fi } # Fonction pour lister les conteneurs @@ -37,10 +88,16 @@ list_containers() { echo -e "${BLUE}═══════════════════════════════════════════════${NC}" echo -e "${GREEN}Liste des conteneurs LXC:${NC}" echo -e "${BLUE}═══════════════════════════════════════════════${NC}" - pct list + pct list || error_exit "Impossible de lister les conteneurs" echo "" } +# Fonction pour vérifier l'existence d'un conteneur +container_exists() { + local vmid="$1" + pct status "$vmid" &>/dev/null +} + # Fonction pour créer un conteneur create_container() { show_logo @@ -49,279 +106,429 @@ create_container() { # Liste des conteneurs existants list_containers - # Demande du VMID + # Demande et validation du VMID + local vmid while true; do - read -p "Entrez le numéro du conteneur (VMID, ex: 100): " vmid - if [[ ! "$vmid" =~ ^[0-9]+$ ]]; then - echo -e "${RED}Erreur: Veuillez entrer un numéro valide${NC}" + read -rp "Entrez le numéro du conteneur (VMID, 100-999999999): " vmid + + if ! validate_vmid "$vmid"; then + echo -e "${RED}Erreur: VMID invalide (doit être entre 100 et 999999999)${NC}" continue fi - if pct status $vmid &>/dev/null; then + + if container_exists "$vmid"; then echo -e "${RED}Erreur: Le VMID $vmid existe déjà${NC}" continue fi break done - # Nom du conteneur - read -p "Nom du conteneur: " hostname + # Nom du conteneur avec validation + local hostname + while true; do + read -rp "Nom du conteneur (ex: web-server): " hostname + + if [[ -z "$hostname" ]]; then + echo -e "${RED}Erreur: Le nom ne peut pas être vide${NC}" + continue + fi + + if ! validate_hostname "$hostname"; then + echo -e "${RED}Erreur: Nom invalide (lettres, chiffres, tirets uniquement)${NC}" + continue + fi + break + done - # Mot de passe root - read -sp "Mot de passe root: " password - echo "" + # Mot de passe root avec validation + local password password_confirm + while true; do + read -rsp "Mot de passe root (min 8 caractères): " password + echo "" + + if [[ ${#password} -lt 8 ]]; then + echo -e "${RED}Erreur: Le mot de passe doit contenir au moins 8 caractères${NC}" + continue + fi + + read -rsp "Confirmez le mot de passe: " password_confirm + echo "" + + if [[ "$password" != "$password_confirm" ]]; then + echo -e "${RED}Erreur: Les mots de passe ne correspondent pas${NC}" + continue + fi + break + done # Stockage disponible echo -e "\n${BLUE}Stockages disponibles:${NC}" pvesm status | grep -E "^(local|local-lvm)" || pvesm status echo "" - read -p "Stockage pour le conteneur (ex: local-lvm): " storage + + local storage + read -rp "Stockage pour le conteneur (ex: local-lvm): " storage + + if [[ -z "$storage" ]]; then + error_exit "Le stockage ne peut pas être vide" + return 1 + fi + + # Vérifier que le stockage existe + if ! pvesm status | grep -q "^${storage}"; then + error_exit "Le stockage '$storage' n'existe pas" + return 1 + fi # Template disponible echo -e "\n${BLUE}Templates disponibles:${NC}" pveam available | grep -i "system" | head -10 echo "" - read -p "Template à utiliser (ex: debian-12-standard): " template - # Si le template n'est pas téléchargé - if ! pveam list $storage | grep -q "$template"; then - echo -e "${YELLOW}Téléchargement du template...${NC}" - pveam download $storage $template + local template + read -rp "Template à utiliser (ex: debian-12-standard): " template + + if [[ -z "$template" ]]; then + error_exit "Le template ne peut pas être vide" + return 1 fi - # Ressources - read -p "RAM en MB (défaut: 512): " memory - memory=${memory:-512} + # Si le template n'est pas téléchargé + if ! pveam list "$storage" | grep -q "$template"; then + echo -e "${YELLOW}Téléchargement du template...${NC}" + pveam download "$storage" "$template" || { + error_exit "Échec du téléchargement du template" + return 1 + } + fi - read -p "Swap en MB (défaut: 512): " swap - swap=${swap:-512} + # Ressources avec validation + local memory + while true; do + read -rp "RAM en MB (défaut: 512): " memory + memory=${memory:-512} + + if validate_positive_number "$memory"; then + break + fi + echo -e "${RED}Erreur: Valeur invalide${NC}" + done - read -p "Espace disque en GB (défaut: 8): " disk - disk=${disk:-8} + local swap + while true; do + read -rp "Swap en MB (défaut: 512): " swap + swap=${swap:-512} + + if validate_positive_number "$swap"; then + break + fi + echo -e "${RED}Erreur: Valeur invalide${NC}" + done - read -p "Nombre de CPU cores (défaut: 1): " cores - cores=${cores:-1} + local disk + while true; do + read -rp "Espace disque en GB (défaut: 8): " disk + disk=${disk:-8} + + if validate_positive_number "$disk"; then + break + fi + echo -e "${RED}Erreur: Valeur invalide${NC}" + done - # Bridge réseau - read -p "Bridge réseau (défaut: vmbr0): " bridge + local cores + while true; do + read -rp "Nombre de CPU cores (défaut: 1): " cores + cores=${cores:-1} + + if validate_positive_number "$cores"; then + break + fi + echo -e "${RED}Erreur: Valeur invalide${NC}" + done + + # Bridge réseau avec validation + local bridge + read -rp "Bridge réseau (défaut: vmbr0): " bridge bridge=${bridge:-vmbr0} + if [[ ! "$bridge" =~ ^vmbr[0-9]+$ ]]; then + error_exit "Bridge invalide (format: vmbr0, vmbr1, etc.)" + return 1 + fi + # Configuration IP echo -e "\n${BLUE}Configuration réseau:${NC}" echo "1) DHCP" echo "2) IP statique" - read -p "Choix: " net_choice - if [ "$net_choice" = "2" ]; then - read -p "Adresse IP/CIDR (ex: 192.168.1.100/24): " ip - read -p "Passerelle: " gateway - net_config="name=eth0,bridge=$bridge,ip=$ip,gw=$gateway" + local net_choice + read -rp "Choix: " net_choice + + local net_config + if [[ "$net_choice" == "2" ]]; then + local ip gateway + + while true; do + read -rp "Adresse IP/CIDR (ex: 192.168.1.100/24): " ip + + if validate_ip "$ip"; then + break + fi + echo -e "${RED}Erreur: Format IP invalide${NC}" + done + + read -rp "Passerelle: " gateway + net_config="name=eth0,bridge=${bridge},ip=${ip},gw=${gateway}" else - net_config="name=eth0,bridge=$bridge,ip=dhcp" + net_config="name=eth0,bridge=${bridge},ip=dhcp" fi # Démarrage automatique - read -p "Démarrage automatique? (o/n, défaut: n): " autostart + local autostart onboot + read -rp "Démarrage automatique? (o/n, défaut: n): " autostart onboot="0" - [ "$autostart" = "o" ] && onboot="1" + [[ "$autostart" == "o" ]] && onboot="1" # Création du conteneur echo -e "\n${YELLOW}Création du conteneur en cours...${NC}" - pct create $vmid $storage:vztmpl/$template \ - --hostname $hostname \ + if pct create "$vmid" "${storage}:vztmpl/${template}" \ + --hostname "$hostname" \ --password "$password" \ - --memory $memory \ - --swap $swap \ - --rootfs $storage:$disk \ - --cores $cores \ - --net0 $net_config \ - --onboot $onboot \ - --unprivileged 1 - - if [ $? -eq 0 ]; then + --memory "$memory" \ + --swap "$swap" \ + --rootfs "${storage}:${disk}" \ + --cores "$cores" \ + --net0 "$net_config" \ + --onboot "$onboot" \ + --unprivileged 1; then + echo -e "${GREEN}✓ Conteneur $vmid créé avec succès!${NC}" - read -p "Démarrer le conteneur maintenant? (o/n): " start - if [ "$start" = "o" ]; then - pct start $vmid - echo -e "${GREEN}✓ Conteneur démarré${NC}" + + local start + read -rp "Démarrer le conteneur maintenant? (o/n): " start + if [[ "$start" == "o" ]]; then + pct start "$vmid" && echo -e "${GREEN}✓ Conteneur démarré${NC}" fi else - echo -e "${RED}✗ Erreur lors de la création du conteneur${NC}" + error_exit "Échec de la création du conteneur" fi - read -p "Appuyez sur Entrée pour continuer..." + read -rp "Appuyez sur Entrée pour continuer..." } # Fonction pour démarrer un conteneur start_container() { show_logo list_containers - read -p "Numéro du conteneur à démarrer: " vmid - if ! pct status $vmid &>/dev/null; then - echo -e "${RED}Erreur: Le conteneur $vmid n'existe pas${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + local vmid + read -rp "Numéro du conteneur à démarrer: " vmid + + if ! validate_vmid "$vmid"; then + error_exit "VMID invalide" + return 1 + fi + + if ! container_exists "$vmid"; then + error_exit "Le conteneur $vmid n'existe pas" + return 1 fi echo -e "${YELLOW}Démarrage du conteneur $vmid...${NC}" - pct start $vmid - if [ $? -eq 0 ]; then + if pct start "$vmid"; then echo -e "${GREEN}✓ Conteneur $vmid démarré avec succès${NC}" else - echo -e "${RED}✗ Erreur lors du démarrage${NC}" + error_exit "Échec du démarrage" fi - read -p "Appuyez sur Entrée pour continuer..." + read -rp "Appuyez sur Entrée pour continuer..." } # Fonction pour arrêter un conteneur stop_container() { show_logo list_containers - read -p "Numéro du conteneur à arrêter: " vmid - if ! pct status $vmid &>/dev/null; then - echo -e "${RED}Erreur: Le conteneur $vmid n'existe pas${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + local vmid + read -rp "Numéro du conteneur à arrêter: " vmid + + if ! validate_vmid "$vmid"; then + error_exit "VMID invalide" + return 1 + fi + + if ! container_exists "$vmid"; then + error_exit "Le conteneur $vmid n'existe pas" + return 1 fi echo "1) Arrêt normal (shutdown)" echo "2) Arrêt forcé (stop)" - read -p "Choix: " choice - if [ "$choice" = "1" ]; then + local choice + read -rp "Choix: " choice + + if [[ "$choice" == "1" ]]; then echo -e "${YELLOW}Arrêt normal du conteneur $vmid...${NC}" - pct shutdown $vmid + pct shutdown "$vmid" || error_exit "Échec de l'arrêt" else echo -e "${YELLOW}Arrêt forcé du conteneur $vmid...${NC}" - pct stop $vmid + pct stop "$vmid" || error_exit "Échec de l'arrêt forcé" fi - if [ $? -eq 0 ]; then - echo -e "${GREEN}✓ Conteneur $vmid arrêté${NC}" - else - echo -e "${RED}✗ Erreur lors de l'arrêt${NC}" - fi - - read -p "Appuyez sur Entrée pour continuer..." + echo -e "${GREEN}✓ Conteneur $vmid arrêté${NC}" + read -rp "Appuyez sur Entrée pour continuer..." } # Fonction pour redémarrer un conteneur reboot_container() { show_logo list_containers - read -p "Numéro du conteneur à redémarrer: " vmid - if ! pct status $vmid &>/dev/null; then - echo -e "${RED}Erreur: Le conteneur $vmid n'existe pas${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + local vmid + read -rp "Numéro du conteneur à redémarrer: " vmid + + if ! validate_vmid "$vmid"; then + error_exit "VMID invalide" + return 1 + fi + + if ! container_exists "$vmid"; then + error_exit "Le conteneur $vmid n'existe pas" + return 1 fi echo -e "${YELLOW}Redémarrage du conteneur $vmid...${NC}" - pct reboot $vmid - if [ $? -eq 0 ]; then + if pct reboot "$vmid"; then echo -e "${GREEN}✓ Conteneur $vmid redémarré${NC}" else - echo -e "${RED}✗ Erreur lors du redémarrage${NC}" + error_exit "Échec du redémarrage" fi - read -p "Appuyez sur Entrée pour continuer..." + read -rp "Appuyez sur Entrée pour continuer..." } # Fonction pour supprimer un conteneur delete_container() { show_logo list_containers - read -p "Numéro du conteneur à supprimer: " vmid - if ! pct status $vmid &>/dev/null; then - echo -e "${RED}Erreur: Le conteneur $vmid n'existe pas${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + local vmid + read -rp "Numéro du conteneur à supprimer: " vmid + + if ! validate_vmid "$vmid"; then + error_exit "VMID invalide" + return 1 + fi + + if ! container_exists "$vmid"; then + error_exit "Le conteneur $vmid n'existe pas" + return 1 fi echo -e "${RED}⚠ ATTENTION: Cette action est irréversible!${NC}" - read -p "Êtes-vous sûr de vouloir supprimer le conteneur $vmid? (oui/non): " confirm - if [ "$confirm" != "oui" ]; then + local confirm + read -rp "Tapez exactement 'SUPPRIMER' pour confirmer: " confirm + + if [[ "$confirm" != "SUPPRIMER" ]]; then echo -e "${YELLOW}Suppression annulée${NC}" - read -p "Appuyez sur Entrée pour continuer..." + read -rp "Appuyez sur Entrée pour continuer..." return fi # Vérifier si le conteneur est en cours d'exécution - if pct status $vmid | grep -q "running"; then + if pct status "$vmid" | grep -q "running"; then echo -e "${YELLOW}Arrêt du conteneur en cours...${NC}" - pct stop $vmid + pct stop "$vmid" || true sleep 2 fi echo -e "${YELLOW}Suppression du conteneur $vmid...${NC}" - pct destroy $vmid --purge - if [ $? -eq 0 ]; then + if pct destroy "$vmid" --purge; then echo -e "${GREEN}✓ Conteneur $vmid supprimé avec succès${NC}" else - echo -e "${RED}✗ Erreur lors de la suppression${NC}" + error_exit "Échec de la suppression" fi - read -p "Appuyez sur Entrée pour continuer..." + read -rp "Appuyez sur Entrée pour continuer..." } # Fonction pour déverrouiller un conteneur unlock_container() { show_logo list_containers - read -p "Numéro du conteneur à déverrouiller: " vmid - if ! pct status $vmid &>/dev/null; then - echo -e "${RED}Erreur: Le conteneur $vmid n'existe pas${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + local vmid + read -rp "Numéro du conteneur à déverrouiller: " vmid + + if ! validate_vmid "$vmid"; then + error_exit "VMID invalide" + return 1 + fi + + if ! container_exists "$vmid"; then + error_exit "Le conteneur $vmid n'existe pas" + return 1 fi echo -e "${YELLOW}Déverrouillage du conteneur $vmid...${NC}" - pct unlock $vmid - if [ $? -eq 0 ]; then + if pct unlock "$vmid"; then echo -e "${GREEN}✓ Conteneur $vmid déverrouillé${NC}" else - echo -e "${RED}✗ Erreur lors du déverrouillage${NC}" + error_exit "Échec du déverrouillage" fi - read -p "Appuyez sur Entrée pour continuer..." + read -rp "Appuyez sur Entrée pour continuer..." } # Fonction pour backup local backup_local() { show_logo list_containers - read -p "Numéro du conteneur à sauvegarder: " vmid - if ! pct status $vmid &>/dev/null; then - echo -e "${RED}Erreur: Le conteneur $vmid n'existe pas${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + local vmid + read -rp "Numéro du conteneur à sauvegarder: " vmid + + if ! validate_vmid "$vmid"; then + error_exit "VMID invalide" + return 1 + fi + + if ! container_exists "$vmid"; then + error_exit "Le conteneur $vmid n'existe pas" + return 1 fi # Stockage disponible pour backup echo -e "\n${BLUE}Stockages disponibles:${NC}" pvesm status | grep -v "^Disk" echo "" - read -p "Stockage pour la sauvegarde (défaut: local): " dumpdir + + local dumpdir + read -rp "Stockage pour la sauvegarde (défaut: local): " dumpdir dumpdir=${dumpdir:-local} + # Vérifier que le stockage existe + if ! pvesm status | grep -q "^${dumpdir}"; then + error_exit "Le stockage '$dumpdir' n'existe pas" + return 1 + fi + # Type de compression echo -e "\n${BLUE}Type de compression:${NC}" echo "1) gzip (rapide, compression moyenne)" echo "2) lzo (très rapide, faible compression)" echo "3) zstd (bon compromis vitesse/compression)" - read -p "Choix (défaut: 1): " compress_choice + + local compress_choice compress + read -rp "Choix (défaut: 1): " compress_choice case $compress_choice in 2) compress="lzo";; @@ -334,7 +541,9 @@ backup_local() { echo "1) Snapshot (plus rapide, nécessite ZFS/LVM)" echo "2) Stop (arrêt du conteneur)" echo "3) Suspend (suspension temporaire)" - read -p "Choix (défaut: 1): " mode_choice + + local mode_choice mode + read -rp "Choix (défaut: 1): " mode_choice case $mode_choice in 2) mode="stop";; @@ -343,16 +552,15 @@ backup_local() { esac echo -e "\n${YELLOW}Création de la sauvegarde...${NC}" - vzdump $vmid --storage $dumpdir --mode $mode --compress $compress - if [ $? -eq 0 ]; then + if vzdump "$vmid" --storage "$dumpdir" --mode "$mode" --compress "$compress"; then echo -e "${GREEN}✓ Sauvegarde créée avec succès${NC}" echo -e "${BLUE}Emplacement: $dumpdir${NC}" else - echo -e "${RED}✗ Erreur lors de la sauvegarde${NC}" + error_exit "Échec de la sauvegarde" fi - read -p "Appuyez sur Entrée pour continuer..." + read -rp "Appuyez sur Entrée pour continuer..." } # Fonction pour restaurer un backup @@ -365,40 +573,67 @@ restore_backup() { pvesm list local | grep "vzdump" || echo "Aucune sauvegarde trouvée dans 'local'" echo "" - read -p "Nom complet du fichier de sauvegarde: " backup_file - read -p "Nouveau VMID pour la restauration: " new_vmid + local backup_file + read -rp "Nom complet du fichier de sauvegarde: " backup_file - if pct status $new_vmid &>/dev/null; then - echo -e "${RED}Erreur: Le VMID $new_vmid existe déjà${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + if [[ -z "$backup_file" ]]; then + error_exit "Le nom du fichier ne peut pas être vide" + return 1 fi - read -p "Stockage pour le conteneur (défaut: local-lvm): " storage + local new_vmid + while true; do + read -rp "Nouveau VMID pour la restauration: " new_vmid + + if ! validate_vmid "$new_vmid"; then + echo -e "${RED}VMID invalide${NC}" + continue + fi + + if container_exists "$new_vmid"; then + echo -e "${RED}Erreur: Le VMID $new_vmid existe déjà${NC}" + continue + fi + break + done + + local storage + read -rp "Stockage pour le conteneur (défaut: local-lvm): " storage storage=${storage:-local-lvm} - echo -e "\n${YELLOW}Restauration en cours...${NC}" - pct restore $new_vmid local:backup/$backup_file --storage $storage - - if [ $? -eq 0 ]; then - echo -e "${GREEN}✓ Sauvegarde restaurée avec succès sur VMID $new_vmid${NC}" - else - echo -e "${RED}✗ Erreur lors de la restauration${NC}" + # Vérifier que le stockage existe + if ! pvesm status | grep -q "^${storage}"; then + error_exit "Le stockage '$storage' n'existe pas" + return 1 fi - read -p "Appuyez sur Entrée pour continuer..." + echo -e "\n${YELLOW}Restauration en cours...${NC}" + + if pct restore "$new_vmid" "local:backup/${backup_file}" --storage "$storage"; then + echo -e "${GREEN}✓ Sauvegarde restaurée avec succès sur VMID $new_vmid${NC}" + else + error_exit "Échec de la restauration" + fi + + read -rp "Appuyez sur Entrée pour continuer..." } # Fonction pour afficher les informations d'un conteneur show_container_info() { show_logo list_containers - read -p "Numéro du conteneur: " vmid - if ! pct status $vmid &>/dev/null; then - echo -e "${RED}Erreur: Le conteneur $vmid n'existe pas${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + local vmid + read -rp "Numéro du conteneur: " vmid + + if ! validate_vmid "$vmid"; then + error_exit "VMID invalide" + return 1 + fi + + if ! container_exists "$vmid"; then + error_exit "Le conteneur $vmid n'existe pas" + return 1 fi echo -e "\n${BLUE}═══════════════════════════════════════════════${NC}" @@ -406,75 +641,107 @@ show_container_info() { echo -e "${BLUE}═══════════════════════════════════════════════${NC}\n" echo -e "${YELLOW}Statut:${NC}" - pct status $vmid + pct status "$vmid" || true echo "" echo -e "${YELLOW}Configuration:${NC}" - pct config $vmid + pct config "$vmid" || true echo "" echo -e "${YELLOW}Utilisation des ressources:${NC}" - pct df $vmid 2>/dev/null || echo "Conteneur arrêté" + pct df "$vmid" 2>/dev/null || echo "Conteneur arrêté" echo "" - read -p "Appuyez sur Entrée pour continuer..." + read -rp "Appuyez sur Entrée pour continuer..." } # Fonction pour entrer dans un conteneur enter_container() { show_logo list_containers - read -p "Numéro du conteneur: " vmid - if ! pct status $vmid &>/dev/null; then - echo -e "${RED}Erreur: Le conteneur $vmid n'existe pas${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + local vmid + read -rp "Numéro du conteneur: " vmid + + if ! validate_vmid "$vmid"; then + error_exit "VMID invalide" + return 1 fi - if ! pct status $vmid | grep -q "running"; then - echo -e "${RED}Erreur: Le conteneur doit être démarré${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + if ! container_exists "$vmid"; then + error_exit "Le conteneur $vmid n'existe pas" + return 1 + fi + + if ! pct status "$vmid" | grep -q "running"; then + error_exit "Le conteneur doit être démarré" + return 1 fi echo -e "${GREEN}Connexion au conteneur $vmid...${NC}" echo -e "${YELLOW}(Tapez 'exit' pour quitter)${NC}\n" - pct enter $vmid + pct enter "$vmid" || error_exit "Échec de la connexion" } # Fonction pour cloner un conteneur clone_container() { show_logo list_containers - read -p "Numéro du conteneur source: " source_vmid - if ! pct status $source_vmid &>/dev/null; then - echo -e "${RED}Erreur: Le conteneur $source_vmid n'existe pas${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + local source_vmid + read -rp "Numéro du conteneur source: " source_vmid + + if ! validate_vmid "$source_vmid"; then + error_exit "VMID source invalide" + return 1 fi - read -p "Numéro du nouveau conteneur: " new_vmid - - if pct status $new_vmid &>/dev/null; then - echo -e "${RED}Erreur: Le VMID $new_vmid existe déjà${NC}" - read -p "Appuyez sur Entrée pour continuer..." - return + if ! container_exists "$source_vmid"; then + error_exit "Le conteneur $source_vmid n'existe pas" + return 1 fi - read -p "Nom du nouveau conteneur: " new_hostname + local new_vmid + while true; do + read -rp "Numéro du nouveau conteneur: " new_vmid + + if ! validate_vmid "$new_vmid"; then + echo -e "${RED}VMID invalide${NC}" + continue + fi + + if container_exists "$new_vmid"; then + echo -e "${RED}Erreur: Le VMID $new_vmid existe déjà${NC}" + continue + fi + break + done + + local new_hostname + while true; do + read -rp "Nom du nouveau conteneur: " new_hostname + + if [[ -z "$new_hostname" ]]; then + echo -e "${RED}Le nom ne peut pas être vide${NC}" + continue + fi + + if ! validate_hostname "$new_hostname"; then + echo -e "${RED}Nom invalide${NC}" + continue + fi + break + done echo -e "\n${YELLOW}Clonage en cours...${NC}" - pct clone $source_vmid $new_vmid --hostname $new_hostname - if [ $? -eq 0 ]; then + if pct clone "$source_vmid" "$new_vmid" --hostname "$new_hostname"; then echo -e "${GREEN}✓ Conteneur cloné avec succès${NC}" else - echo -e "${RED}✗ Erreur lors du clonage${NC}" + error_exit "Échec du clonage" fi - read -p "Appuyez sur Entrée pour continuer..." + read -rp "Appuyez sur Entrée pour continuer..." } # Menu principal @@ -496,27 +763,34 @@ main_menu() { echo "12) Cloner un conteneur" echo "0) Quitter" echo "" - read -p "Votre choix: " choice + + local choice + read -rp "Votre choix: " choice case $choice in - 1) show_logo; list_containers; read -p "Appuyez sur Entrée pour continuer...";; - 2) create_container;; - 3) start_container;; - 4) stop_container;; - 5) reboot_container;; - 6) delete_container;; - 7) unlock_container;; - 8) backup_local;; - 9) restore_backup;; - 10) show_container_info;; - 11) enter_container;; - 12) clone_container;; + 1) show_logo; list_containers; read -rp "Appuyez sur Entrée pour continuer...";; + 2) create_container || true;; + 3) start_container || true;; + 4) stop_container || true;; + 5) reboot_container || true;; + 6) delete_container || true;; + 7) unlock_container || true;; + 8) backup_local || true;; + 9) restore_backup || true;; + 10) show_container_info || true;; + 11) enter_container || true;; + 12) clone_container || true;; 0) echo -e "${GREEN}Au revoir!${NC}"; exit 0;; *) echo -e "${RED}Choix invalide${NC}"; sleep 2;; esac done } -# Vérification et lancement -check_proxmox -main_menu \ No newline at end of file +# Point d'entrée principal +main() { + check_proxmox + main_menu +} + +# Lancement du script +main \ No newline at end of file