Actualiser lxc_manager.sh

This commit is contained in:
2025-12-31 08:05:20 +00:00
parent 1707e2d26e
commit 0a5e4bc02e

View File

@@ -2,7 +2,7 @@
############################################# #############################################
# Script de Gestion LXC pour Proxmox VE # Script de Gestion LXC pour Proxmox VE
# Date: 18/12/2025 # Auteur: Généré par Claude
# Description: Gestion complète des conteneurs LXC # Description: Gestion complète des conteneurs LXC
############################################# #############################################
@@ -14,8 +14,12 @@ readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m' readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m' readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m' readonly BLUE='\033[0;34m'
readonly MAGENTA='\033[0;35m'
readonly NC='\033[0m' # No Color readonly NC='\033[0m' # No Color
# Variable globale pour la protection
PROTECTION_ENABLED=true
# Fonction pour gérer les erreurs # Fonction pour gérer les erreurs
error_exit() { error_exit() {
echo -e "${RED}Erreur: $1${NC}" >&2 echo -e "${RED}Erreur: $1${NC}" >&2
@@ -59,15 +63,76 @@ validate_positive_number() {
return 0 return 0
} }
# Fonction pour vérifier si un conteneur a la protection activée
check_container_protection() {
local vmid="$1"
local protection_status
protection_status=$(pct config "$vmid" | grep "^protection:" | awk '{print $2}')
if [[ "$protection_status" == "1" ]]; then
return 0 # Protection activée
else
return 1 # Protection désactivée
fi
}
# Fonction pour activer/désactiver la protection d'un conteneur
toggle_protection() {
show_logo
list_containers
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}État actuel de la protection:${NC}"
if check_container_protection "$vmid"; then
echo -e "${GREEN}✓ Protection activée${NC}"
echo ""
read -rp "Désactiver la protection? (o/n): " choice
if [[ "$choice" == "o" ]]; then
pct set "$vmid" --protection 0
echo -e "${YELLOW}✓ Protection désactivée pour le conteneur $vmid${NC}"
fi
else
echo -e "${YELLOW}✗ Protection désactivée${NC}"
echo ""
read -rp "Activer la protection? (o/n): " choice
if [[ "$choice" == "o" ]]; then
pct set "$vmid" --protection 1
echo -e "${GREEN}✓ Protection activée pour le conteneur $vmid${NC}"
fi
fi
read -rp "Appuyez sur Entrée pour continuer..."
}
# Fonction pour afficher le logo # Fonction pour afficher le logo
show_logo() { show_logo() {
clear clear
echo -e "${BLUE}" echo -e "${BLUE}"
echo "╔═══════════════════════════════════════════════╗" echo "╔═══════════════════════════════════════════════╗"
echo "║ GESTIONNAIRE LXC PROXMOX VE ║" echo "║ GESTIONNAIRE LXC PROXMOX VE ║"
echo "║ Version 2.0 - Sécurisé ║" echo "║ Version 2.1 - Sécurisé ║"
echo "╚═══════════════════════════════════════════════╝" echo "╚═══════════════════════════════════════════════╝"
echo -e "${NC}" echo -e "${NC}"
if [[ "$PROTECTION_ENABLED" == true ]]; then
echo -e "${GREEN}🔒 Mode protection: ACTIVÉ${NC}\n"
else
echo -e "${YELLOW}🔓 Mode protection: DÉSACTIVÉ${NC}\n"
fi
} }
# Fonction pour vérifier si on est sur Proxmox # Fonction pour vérifier si on est sur Proxmox
@@ -163,22 +228,28 @@ create_container() {
# Stockage disponible # Stockage disponible
echo -e "\n${BLUE}Stockages disponibles:${NC}" echo -e "\n${BLUE}Stockages disponibles:${NC}"
pvesm status | grep -E "^(local|local-lvm)" || pvesm status mapfile -t storages_list < <(pvesm status | awk 'NR>1 {print $1}')
if [[ ${#storages_list[@]} -eq 0 ]]; then
error_exit "Aucun stockage disponible"
return 1
fi
for i in "${!storages_list[@]}"; do
echo "$((i+1))) ${storages_list[$i]}"
done
echo "" echo ""
local storage local storage_choice
read -rp "Stockage pour le conteneur (ex: local-lvm): " storage read -rp "Choisir le stockage pour le conteneur (défaut: 1): " storage_choice
storage_choice=${storage_choice:-1}
if [[ -z "$storage" ]]; then if [[ ! "$storage_choice" =~ ^[0-9]+$ ]] || [[ $storage_choice -lt 1 ]] || [[ $storage_choice -gt ${#storages_list[@]} ]]; then
error_exit "Le stockage ne peut pas être vide" error_exit "Choix invalide"
return 1 return 1
fi fi
# Vérifier que le stockage existe local storage="${storages_list[$((storage_choice-1))]}"
if ! pvesm status | grep -q "^${storage}"; then
error_exit "Le stockage '$storage' n'existe pas"
return 1
fi
# Template disponible # Template disponible
echo -e "\n${BLUE}Templates disponibles:${NC}" echo -e "\n${BLUE}Templates disponibles:${NC}"
@@ -290,6 +361,12 @@ create_container() {
onboot="0" onboot="0"
[[ "$autostart" == "o" ]] && onboot="1" [[ "$autostart" == "o" ]] && onboot="1"
# Protection
local protection
read -rp "Activer la protection contre la suppression? (o/n, défaut: n): " protection
local protection_flag=""
[[ "$protection" == "o" ]] && protection_flag="--protection 1"
# Création du conteneur # Création du conteneur
echo -e "\n${YELLOW}Création du conteneur en cours...${NC}" echo -e "\n${YELLOW}Création du conteneur en cours...${NC}"
@@ -302,7 +379,8 @@ create_container() {
--cores "$cores" \ --cores "$cores" \
--net0 "$net_config" \ --net0 "$net_config" \
--onboot "$onboot" \ --onboot "$onboot" \
--unprivileged 1; then --unprivileged 1 \
$protection_flag; then
echo -e "${GREEN}✓ Conteneur $vmid créé avec succès!${NC}" echo -e "${GREEN}✓ Conteneur $vmid créé avec succès!${NC}"
@@ -430,9 +508,27 @@ delete_container() {
return 1 return 1
fi fi
# Vérifier si la protection est activée
if check_container_protection "$vmid"; then
echo -e "${RED}⚠ ATTENTION: Ce conteneur a la protection activée!${NC}"
echo -e "${YELLOW}La protection empêche la suppression accidentelle.${NC}\n"
read -rp "Désactiver la protection et continuer? (o/n): " disable_protection
if [[ "$disable_protection" == "o" ]]; then
pct set "$vmid" --protection 0
echo -e "${YELLOW}✓ Protection désactivée${NC}\n"
else
echo -e "${YELLOW}Suppression annulée${NC}"
read -rp "Appuyez sur Entrée pour continuer..."
return
fi
fi
echo -e "${RED}⚠ ATTENTION: Cette action est irréversible!${NC}" echo -e "${RED}⚠ ATTENTION: Cette action est irréversible!${NC}"
local confirm local confirm
if [[ "$PROTECTION_ENABLED" == true ]]; then
read -rp "Tapez exactement 'SUPPRIMER' pour confirmer: " confirm read -rp "Tapez exactement 'SUPPRIMER' pour confirmer: " confirm
if [[ "$confirm" != "SUPPRIMER" ]]; then if [[ "$confirm" != "SUPPRIMER" ]]; then
@@ -440,6 +536,14 @@ delete_container() {
read -rp "Appuyez sur Entrée pour continuer..." read -rp "Appuyez sur Entrée pour continuer..."
return return
fi fi
else
read -rp "Confirmer la suppression? (o/n): " confirm
if [[ "$confirm" != "o" ]]; then
echo -e "${YELLOW}Suppression annulée${NC}"
read -rp "Appuyez sur Entrée pour continuer..."
return
fi
fi
# Vérifier si le conteneur est en cours d'exécution # 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
@@ -507,20 +611,54 @@ backup_local() {
fi fi
# Stockage disponible pour backup # Stockage disponible pour backup
echo -e "\n${BLUE}Stockages disponibles:${NC}" echo -e "\n${BLUE}Stockages disponibles pour les sauvegardes:${NC}"
pvesm status | grep -v "^Disk"
# Filtrer uniquement les stockages avec content type "backup" ou "vztmpl,backup"
mapfile -t storages_backup < <(pvesm status -content backup 2>/dev/null | awk 'NR>1 {print $1}')
if [[ ${#storages_backup[@]} -eq 0 ]]; then
# Fallback: essayer de lister tous les stockages actifs
echo -e "${YELLOW}Aucun stockage spécifique pour backup trouvé, affichage de tous les stockages...${NC}"
mapfile -t storages_backup < <(pvesm status | awk 'NR>1 && $2=="active" {print $1}')
if [[ ${#storages_backup[@]} -eq 0 ]]; then
error_exit "Aucun stockage disponible"
return 1
fi
fi
for i in "${!storages_backup[@]}"; do
# Afficher les informations du stockage
local storage_info=$(pvesm status | grep "^${storages_backup[$i]}" | awk '{print $1" ("$3")"}')
echo "$((i+1))) $storage_info"
done
echo ""
echo -e "${YELLOW}Note: Seuls les stockages configurés pour les backups sont affichés${NC}"
echo "" echo ""
local dumpdir local dumpdir_choice
read -rp "Stockage pour la sauvegarde (défaut: local): " dumpdir read -rp "Choisir le stockage pour la sauvegarde (défaut: 1): " dumpdir_choice
dumpdir=${dumpdir:-local} dumpdir_choice=${dumpdir_choice:-1}
# Vérifier que le stockage existe if [[ ! "$dumpdir_choice" =~ ^[0-9]+$ ]] || [[ $dumpdir_choice -lt 1 ]] || [[ $dumpdir_choice -gt ${#storages_backup[@]} ]]; then
if ! pvesm status | grep -q "^${dumpdir}"; then error_exit "Choix invalide"
error_exit "Le stockage '$dumpdir' n'existe pas"
return 1 return 1
fi fi
local dumpdir="${storages_backup[$((dumpdir_choice-1))]}"
# Vérifier que le stockage accepte bien les backups
echo -e "${BLUE}Vérification du stockage...${NC}"
if ! pvesm status -content backup 2>/dev/null | grep -q "^${dumpdir}"; then
echo -e "${YELLOW}⚠ Avertissement: Ce stockage pourrait ne pas être configuré pour les backups${NC}"
read -rp "Continuer quand même? (o/n): " continue_backup
if [[ "$continue_backup" != "o" ]]; then
echo -e "${YELLOW}Sauvegarde annulée${NC}"
read -rp "Appuyez sur Entrée pour continuer..."
return
fi
fi
# Type de compression # Type de compression
echo -e "\n${BLUE}Type de compression:${NC}" echo -e "\n${BLUE}Type de compression:${NC}"
echo "1) gzip (rapide, compression moyenne)" echo "1) gzip (rapide, compression moyenne)"
@@ -568,19 +706,69 @@ restore_backup() {
show_logo show_logo
echo -e "${GREEN}Restauration d'une sauvegarde${NC}\n" echo -e "${GREEN}Restauration d'une sauvegarde${NC}\n"
# Lister les sauvegardes disponibles # Lister tous les stockages disponibles
echo -e "${BLUE}Sauvegardes disponibles:${NC}" echo -e "${BLUE}Stockages disponibles:${NC}"
pvesm list local | grep "vzdump" || echo "Aucune sauvegarde trouvée dans 'local'" mapfile -t storages < <(pvesm status | awk 'NR>1 {print $1}')
echo ""
local backup_file if [[ ${#storages[@]} -eq 0 ]]; then
read -rp "Nom complet du fichier de sauvegarde: " backup_file error_exit "Aucun stockage disponible"
if [[ -z "$backup_file" ]]; then
error_exit "Le nom du fichier ne peut pas être vide"
return 1 return 1
fi fi
for i in "${!storages[@]}"; do
echo "$((i+1))) ${storages[$i]}"
done
echo ""
# Sélection du stockage source
local storage_choice
read -rp "Choisir le stockage contenant les sauvegardes (défaut: 1): " storage_choice
storage_choice=${storage_choice:-1}
if [[ ! "$storage_choice" =~ ^[0-9]+$ ]] || [[ $storage_choice -lt 1 ]] || [[ $storage_choice -gt ${#storages[@]} ]]; then
error_exit "Choix invalide"
return 1
fi
local selected_storage="${storages[$((storage_choice-1))]}"
# Lister les sauvegardes disponibles sur ce stockage
echo -e "\n${BLUE}Sauvegardes disponibles sur '$selected_storage':${NC}"
mapfile -t backups < <(pvesm list "$selected_storage" | grep "vzdump" | awk '{print $1}' | sed "s/^${selected_storage}://")
if [[ ${#backups[@]} -eq 0 ]]; then
error_exit "Aucune sauvegarde trouvée sur '$selected_storage'"
return 1
fi
# Afficher les sauvegardes avec numéros
for i in "${!backups[@]}"; do
local backup_name="${backups[$i]}"
# Extraire les informations du nom de fichier (sans le préfixe storage:)
local filename=$(basename "$backup_name")
local vmid_backup=$(echo "$filename" | grep -oP 'vzdump-lxc-\K[0-9]+' || echo "N/A")
local date_backup=$(echo "$filename" | grep -oP '\d{4}_\d{2}_\d{2}-\d{2}_\d{2}_\d{2}' || echo "")
echo -e "$((i+1))) ${MAGENTA}VMID:${NC} $vmid_backup ${MAGENTA}Date:${NC} $date_backup"
echo -e " ${BLUE}Fichier:${NC} $filename"
echo ""
done
# Sélection de la sauvegarde
local backup_choice
read -rp "Choisir la sauvegarde à restaurer (1-${#backups[@]}): " backup_choice
if [[ ! "$backup_choice" =~ ^[0-9]+$ ]] || [[ $backup_choice -lt 1 ]] || [[ $backup_choice -gt ${#backups[@]} ]]; then
error_exit "Choix invalide"
return 1
fi
local selected_backup="${backups[$((backup_choice-1))]}"
echo -e "\n${GREEN}Sauvegarde sélectionnée:${NC} $selected_backup"
# Nouveau VMID
local new_vmid local new_vmid
while true; do while true; do
read -rp "Nouveau VMID pour la restauration: " new_vmid read -rp "Nouveau VMID pour la restauration: " new_vmid
@@ -597,19 +785,30 @@ restore_backup() {
break break
done done
local storage # Stockage pour le conteneur restauré
read -rp "Stockage pour le conteneur (défaut: local-lvm): " storage echo -e "\n${BLUE}Stockages disponibles pour la restauration:${NC}"
storage=${storage:-local-lvm} for i in "${!storages[@]}"; do
echo "$((i+1))) ${storages[$i]}"
done
echo ""
# Vérifier que le stockage existe local restore_storage_choice
if ! pvesm status | grep -q "^${storage}"; then read -rp "Choisir le stockage de destination (défaut: 1): " restore_storage_choice
error_exit "Le stockage '$storage' n'existe pas" restore_storage_choice=${restore_storage_choice:-1}
if [[ ! "$restore_storage_choice" =~ ^[0-9]+$ ]] || [[ $restore_storage_choice -lt 1 ]] || [[ $restore_storage_choice -gt ${#storages[@]} ]]; then
error_exit "Choix invalide"
return 1 return 1
fi fi
echo -e "\n${YELLOW}Restauration en cours...${NC}" local restore_storage="${storages[$((restore_storage_choice-1))]}"
if pct restore "$new_vmid" "local:backup/${backup_file}" --storage "$storage"; then echo -e "\n${YELLOW}Restauration en cours...${NC}"
echo -e "${BLUE}Source:${NC} ${selected_storage}:${selected_backup}"
echo -e "${BLUE}Destination:${NC} VMID $new_vmid sur $restore_storage"
echo ""
if pct restore "$new_vmid" "${selected_storage}:${selected_backup}" --storage "$restore_storage"; then
echo -e "${GREEN}✓ Sauvegarde restaurée avec succès sur VMID $new_vmid${NC}" echo -e "${GREEN}✓ Sauvegarde restaurée avec succès sur VMID $new_vmid${NC}"
else else
error_exit "Échec de la restauration" error_exit "Échec de la restauration"
@@ -644,6 +843,14 @@ show_container_info() {
pct status "$vmid" || true pct status "$vmid" || true
echo "" echo ""
echo -e "${YELLOW}Protection:${NC}"
if check_container_protection "$vmid"; then
echo -e "${GREEN}✓ Activée${NC}"
else
echo -e "${YELLOW}✗ Désactivée${NC}"
fi
echo ""
echo -e "${YELLOW}Configuration:${NC}" echo -e "${YELLOW}Configuration:${NC}"
pct config "$vmid" || true pct config "$vmid" || true
echo "" echo ""
@@ -701,6 +908,46 @@ clone_container() {
return 1 return 1
fi fi
# Vérifier si le conteneur est en cours d'exécution
local is_running=false
if pct status "$source_vmid" | grep -q "running"; then
is_running=true
echo -e "\n${YELLOW}⚠ Le conteneur source est en cours d'exécution${NC}"
echo -e "${BLUE}Options disponibles:${NC}"
echo "1) Arrêter le conteneur avant le clonage (recommandé)"
echo "2) Créer un snapshot et cloner (plus rapide, nécessite ZFS/LVM)"
echo "3) Annuler"
local clone_choice
read -rp "Choix: " clone_choice
case $clone_choice in
1)
echo -e "\n${YELLOW}Arrêt du conteneur...${NC}"
if ! pct shutdown "$source_vmid"; then
echo -e "${YELLOW}Arrêt normal échoué, arrêt forcé...${NC}"
pct stop "$source_vmid" || {
error_exit "Impossible d'arrêter le conteneur"
return 1
}
fi
sleep 2
;;
2)
echo -e "\n${YELLOW}Le clonage avec snapshot sera tenté...${NC}"
;;
3)
echo -e "${YELLOW}Clonage annulé${NC}"
read -rp "Appuyez sur Entrée pour continuer..."
return
;;
*)
error_exit "Choix invalide"
return 1
;;
esac
fi
local new_vmid local new_vmid
while true; do while true; do
read -rp "Numéro du nouveau conteneur: " new_vmid read -rp "Numéro du nouveau conteneur: " new_vmid
@@ -733,12 +980,104 @@ clone_container() {
break break
done done
# Stockage pour le clone
echo -e "\n${BLUE}Stockages disponibles pour le clone:${NC}"
mapfile -t storages_clone < <(pvesm status | awk 'NR>1 {print $1}')
if [[ ${#storages_clone[@]} -eq 0 ]]; then
error_exit "Aucun stockage disponible"
if [[ "$is_running" == true && "$clone_choice" == "1" ]]; then
pct start "$source_vmid" || true
fi
return 1
fi
for i in "${!storages_clone[@]}"; do
echo "$((i+1))) ${storages_clone[$i]}"
done
echo "0) Même stockage que la source"
echo ""
local target_storage_choice
read -rp "Choix (défaut: 0): " target_storage_choice
target_storage_choice=${target_storage_choice:-0}
local storage_param=""
if [[ "$target_storage_choice" != "0" ]]; then
if [[ ! "$target_storage_choice" =~ ^[0-9]+$ ]] || [[ $target_storage_choice -lt 1 ]] || [[ $target_storage_choice -gt ${#storages_clone[@]} ]]; then
error_exit "Choix invalide"
if [[ "$is_running" == true && "$clone_choice" == "1" ]]; then
pct start "$source_vmid" || true
fi
return 1
fi
local target_storage="${storages_clone[$((target_storage_choice-1))]}"
storage_param="--storage $target_storage"
fi
echo -e "\n${YELLOW}Clonage en cours...${NC}" echo -e "\n${YELLOW}Clonage en cours...${NC}"
if pct clone "$source_vmid" "$new_vmid" --hostname "$new_hostname"; then # Tenter le clonage avec snapshot si le conteneur est en cours d'exécution
local clone_cmd="pct clone $source_vmid $new_vmid --hostname $new_hostname"
if [[ -n "$storage_param" ]]; then
clone_cmd="$clone_cmd $storage_param"
fi
# Si le conteneur est en cours d'exécution et qu'on a choisi l'option snapshot
if [[ "$is_running" == true && "$clone_choice" == "2" ]]; then
clone_cmd="$clone_cmd --snapname clone_snapshot"
fi
if eval "$clone_cmd"; then
echo -e "${GREEN}✓ Conteneur cloné avec succès${NC}" echo -e "${GREEN}✓ Conteneur cloné avec succès${NC}"
# Redémarrer le conteneur source si on l'avait arrêté
if [[ "$is_running" == true && "$clone_choice" == "1" ]]; then
echo -e "\n${YELLOW}Redémarrage du conteneur source...${NC}"
pct start "$source_vmid" && echo -e "${GREEN}✓ Conteneur source redémarré${NC}"
fi
else else
error_exit "Échec du clonage" echo -e "${RED}Échec du clonage${NC}"
# Redémarrer le conteneur source si on l'avait arrêté
if [[ "$is_running" == true && "$clone_choice" == "1" ]]; then
echo -e "\n${YELLOW}Redémarrage du conteneur source...${NC}"
pct start "$source_vmid" && echo -e "${GREEN}✓ Conteneur source redémarré${NC}"
fi
error_exit "Le clonage a échoué"
fi
read -rp "Appuyez sur Entrée pour continuer..."
}
# Fonction pour basculer le mode protection global
toggle_global_protection() {
show_logo
if [[ "$PROTECTION_ENABLED" == true ]]; then
echo -e "${GREEN}Mode protection actuellement: ACTIVÉ${NC}"
echo -e "\n${YELLOW}Les confirmations de sécurité sont requises pour les opérations critiques.${NC}"
echo ""
read -rp "Désactiver le mode protection? (o/n): " choice
if [[ "$choice" == "o" ]]; then
PROTECTION_ENABLED=false
echo -e "${YELLOW}✓ Mode protection DÉSACTIVÉ${NC}"
echo -e "${RED}⚠ Attention: Les opérations destructives ne nécessiteront plus de confirmation renforcée${NC}"
fi
else
echo -e "${YELLOW}Mode protection actuellement: DÉSACTIVÉ${NC}"
echo -e "\n${RED}⚠ Les opérations critiques peuvent être exécutées sans confirmation renforcée.${NC}"
echo ""
read -rp "Activer le mode protection? (o/n): " choice
if [[ "$choice" == "o" ]]; then
PROTECTION_ENABLED=true
echo -e "${GREEN}✓ Mode protection ACTIVÉ${NC}"
echo -e "${GREEN}Les opérations critiques nécessiteront des confirmations de sécurité${NC}"
fi
fi fi
read -rp "Appuyez sur Entrée pour continuer..." read -rp "Appuyez sur Entrée pour continuer..."
@@ -761,6 +1100,12 @@ main_menu() {
echo "10) Afficher les informations" echo "10) Afficher les informations"
echo "11) Entrer dans un conteneur" echo "11) Entrer dans un conteneur"
echo "12) Cloner un conteneur" echo "12) Cloner un conteneur"
echo -e "13) ${MAGENTA}Gérer la protection d'un conteneur${NC}"
if [[ "$PROTECTION_ENABLED" == true ]]; then
echo -e "14) ${MAGENTA}Mode protection global (ACTIVÉ)${NC}"
else
echo -e "14) ${MAGENTA}Mode protection global (DÉSACTIVÉ)${NC}"
fi
echo "0) Quitter" echo "0) Quitter"
echo "" echo ""
@@ -780,6 +1125,8 @@ main_menu() {
10) show_container_info || true;; 10) show_container_info || true;;
11) enter_container || true;; 11) enter_container || true;;
12) clone_container || true;; 12) clone_container || true;;
13) toggle_protection || true;;
14) toggle_global_protection || true;;
0) echo -e "${GREEN}Au revoir!${NC}"; exit 0;; 0) echo -e "${GREEN}Au revoir!${NC}"; exit 0;;
*) echo -e "${RED}Choix invalide${NC}"; sleep 2;; *) echo -e "${RED}Choix invalide${NC}"; sleep 2;;
esac esac