#!/bin/bash # Script interactif pour supprimer toutes les Cloud Functions d'un projet Firebase # Utilise les flèches pour naviguer et Entrée pour sélectionner # 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 BOLD='\033[1m' # Fonction pour afficher le menu avec sélection show_menu() { local options=("$@") local selected=0 local num_options=${#options[@]} while true; do clear echo -e "${BLUE}${BOLD}=== Gestionnaire Cloud Functions Firebase ===${NC}\n" if [ ! -z "$CURRENT_PROJECT" ]; then echo -e "${GREEN}Projet actuel: ${BOLD}$CURRENT_PROJECT${NC}\n" fi echo "Utilisez les flèches ↑↓ pour naviguer et Entrée pour sélectionner:\n" for i in "${!options[@]}"; do if [ $i -eq $selected ]; then echo -e "${GREEN}► ${options[$i]}${NC}" else echo -e " ${options[$i]}" fi done # Lire une seule touche read -rsn1 key case $key in $'\033') # Séquence d'échappement pour les flèches read -rsn2 key case $key in '[A') # Flèche haut ((selected--)) if [ $selected -lt 0 ]; then selected=$((num_options-1)) fi ;; '[B') # Flèche bas ((selected++)) if [ $selected -ge $num_options ]; then selected=0 fi ;; esac ;; '') # Entrée return $selected ;; 'q'|'Q') # Quitter echo -e "\n${YELLOW}Au revoir!${NC}" exit 0 ;; esac done } # Fonction pour vérifier si gcloud est installé check_gcloud() { if ! command -v gcloud &> /dev/null; then echo -e "${RED}Erreur: gcloud CLI n'est pas installé.${NC}" echo "Veuillez installer Google Cloud SDK: https://cloud.google.com/sdk/docs/install" exit 1 fi } # Fonction pour obtenir le projet actuel get_current_project() { CURRENT_PROJECT=$(gcloud config get-value project 2>/dev/null) if [ -z "$CURRENT_PROJECT" ]; then echo -e "${YELLOW}Aucun projet configuré.${NC}" CURRENT_PROJECT="Aucun" fi } # Fonction pour afficher les informations de débogage show_debug_info() { clear echo -e "${BLUE}${BOLD}=== Informations de débogage ===${NC}\n" echo -e "${YELLOW}1. Version de gcloud:${NC}" gcloud version 2>/dev/null || echo "Erreur lors de la récupération de la version" echo "" echo -e "${YELLOW}2. Configuration actuelle:${NC}" gcloud config list 2>/dev/null || echo "Erreur lors de la récupération de la configuration" echo "" echo -e "${YELLOW}3. Comptes authentifiés:${NC}" gcloud auth list 2>/dev/null || echo "Erreur lors de la récupération des comptes" echo "" echo -e "${YELLOW}4. Test de la commande projects list (brute):${NC}" echo "Commande: gcloud projects list" gcloud projects list 2>&1 || echo "Erreur lors de l'exécution" echo "" echo -e "${YELLOW}5. Test avec format JSON:${NC}" echo "Commande: gcloud projects list --format=json" gcloud projects list --format="json" 2>&1 | head -20 || echo "Erreur lors de l'exécution" echo "" echo -e "${YELLOW}6. Permissions et quotas:${NC}" echo "Commande: gcloud projects list --limit=1" gcloud projects list --limit=1 2>&1 || echo "Erreur lors de l'exécution" echo "" } # Fonction pour gérer l'authentification handle_authentication() { clear echo -e "${RED}${BOLD}=== Erreur d'authentification ===${NC}\n" echo -e "${YELLOW}Aucun projet trouvé ou erreur d'authentification.${NC}\n" local auth_options=("Se connecter maintenant (gcloud auth login)" "Réessayer" "← Retour au menu principal") echo "Que souhaitez-vous faire ?\n" show_menu "${auth_options[@]}" local choice=$? case $choice in 0) # Se connecter echo -e "\n${BLUE}Lancement de l'authentification...${NC}" echo -e "${YELLOW}Une page web va s'ouvrir pour vous connecter.${NC}\n" if gcloud auth login; then echo -e "\n${GREEN}Authentification réussie!${NC}" sleep 2 return 0 else echo -e "\n${RED}Échec de l'authentification.${NC}" read -p "Appuyez sur Entrée pour continuer..." return 1 fi ;; 1) # Réessayer return 0 ;; 2) # Retour return 1 ;; esac } # Fonction pour récupérer la liste des projets get_projects_list() { local projects=() # Vérifier si l'utilisateur est connecté local auth_status=$(gcloud auth list --format="value(account)" 2>/dev/null | head -1) if [ -z "$auth_status" ]; then echo -e "${RED}Vous n'êtes pas connecté à GCP.${NC}" return 1 fi echo -e "${BLUE}Récupération des projets...${NC}" # Méthode 1: Utiliser --format=json pour éviter les problèmes de parsing local temp_file=$(mktemp) gcloud projects list --format="json" > "$temp_file" 2>/dev/null if [ -s "$temp_file" ]; then # Extraire les IDs de projet du JSON while read -r project_id; do if [ ! -z "$project_id" ]; then projects+=("$project_id") fi done < <(cat "$temp_file" | grep -o '"projectId": "[^"]*"' | cut -d '"' -f 4) else # Méthode 2: Essayer avec la méthode originale gcloud projects list --format="table(projectId)" --sort-by=projectId > "$temp_file" 2>&1 while IFS= read -r line; do if [[ $line =~ ^[a-zA-Z0-9-]+[[:space:]] ]]; then project_id=$(echo "$line" | awk '{print $1}') if [ ! -z "$project_id" ]; then projects+=("$project_id") fi fi done < <(cat "$temp_file" | tail -n +2) fi # Nettoyer le fichier temporaire rm -f "$temp_file" # Retourner les projets via une variable globale PROJECTS_LIST=("${projects[@]}") return 0 } # Fonction pour sélectionner un projet de manière interactive avec filtrage select_project_interactive() { echo -e "\n${BLUE}Récupération de la liste des projets...${NC}" # Récupérer tous les projets disponibles local all_projects=() if ! get_projects_list; then if ! handle_authentication; then return 1 fi if ! get_projects_list; then echo -e "${RED}Impossible de récupérer la liste des projets.${NC}" read -p "Appuyez sur Entrée pour continuer..." return 1 fi fi all_projects=("${PROJECTS_LIST[@]}") if [ ${#all_projects[@]} -eq 0 ]; then echo -e "${RED}Aucun projet accessible trouvé.${NC}" echo -e "${YELLOW}Cela peut être dû à:${NC}" echo -e " • Aucun projet associé à votre compte" echo -e " • Permissions insuffisantes" echo -e " • Problème de configuration gcloud" echo "" local retry_options=("Réessayer" "Se reconnecter" "Spécifier manuellement l'ID du projet" "Afficher les détails de débogage" "← Retour au menu principal") echo "Que souhaitez-vous faire ?\n" show_menu "${retry_options[@]}" local retry_choice=$? case $retry_choice in 0) # Réessayer return select_project_interactive ;; 1) # Se reconnecter if handle_authentication; then return select_project_interactive else return 1 fi ;; 2) # Spécifier manuellement l'ID du projet clear echo -e "${BLUE}${BOLD}=== Spécifier l'ID du projet ===${NC}\n" echo -e "${YELLOW}Entrez l'ID du projet Firebase/GCP:${NC}" echo -e "(exemple: my-project-12345)\n" read -p "> " manual_project_id if [ -z "$manual_project_id" ]; then echo -e "\n${RED}Aucun ID de projet spécifié.${NC}" read -p "Appuyez sur Entrée pour continuer..." return 1 fi echo -e "\n${BLUE}Vérification du projet: $manual_project_id${NC}" if gcloud projects describe "$manual_project_id" &>/dev/null; then echo -e "${GREEN}Projet trouvé!${NC}" all_projects=("$manual_project_id") else echo -e "${RED}Projet non trouvé ou vous n'avez pas les permissions nécessaires.${NC}" read -p "Appuyez sur Entrée pour continuer..." return 1 fi ;; 3) # Afficher les détails de débogage show_debug_info read -p "Appuyez sur Entrée pour continuer..." return 1 ;; 4) # Retour return 1 ;; esac fi # Ajouter option de retour all_projects+=("← Retour au menu principal") local selected=0 local filter="" local filtered_projects=() # Fonction pour filtrer les projets filter_projects() { filtered_projects=() for project in "${all_projects[@]}"; do if [[ "$project" == *"$filter"* ]]; then filtered_projects+=("$project") fi done # Réajuster la sélection si nécessaire if [ $selected -ge ${#filtered_projects[@]} ]; then selected=0 fi } # Initialiser le filtre filter_projects while true; do clear echo -e "${BLUE}${BOLD}=== Sélection du projet ===${NC}\n" echo -e "${YELLOW}Projet actuel: ${BOLD}${CURRENT_PROJECT:-"Aucun"}${NC}" echo "" echo -e "${YELLOW}Tapez pour filtrer, utilisez ↑↓ pour naviguer, Entrée pour sélectionner:${NC}" echo -e "Filtre: ${BOLD}$filter${NC}" echo "" # Afficher les projets filtrés if [ ${#filtered_projects[@]} -eq 0 ]; then echo -e "${RED}Aucun projet trouvé pour le filtre '$filter'${NC}" else for i in "${!filtered_projects[@]}"; do if [ $i -eq $selected ]; then echo -e "${GREEN}► ${filtered_projects[$i]}${NC}" else echo -e " ${filtered_projects[$i]}" fi done fi echo -e "\n${BLUE}Commandes: [Backspace] Effacer filtre | [Esc] Annuler${NC}" # Lire une seule touche read -rsn1 key case $key in $'\033') # Séquence d'échappement read -rsn2 key case $key in '[A') # Flèche haut if [ ${#filtered_projects[@]} -gt 0 ]; then ((selected--)) if [ $selected -lt 0 ]; then selected=$((${#filtered_projects[@]}-1)) fi fi ;; '[B') # Flèche bas if [ ${#filtered_projects[@]} -gt 0 ]; then ((selected++)) if [ $selected -ge ${#filtered_projects[@]} ]; then selected=0 fi fi ;; esac ;; '') # Entrée if [ ${#filtered_projects[@]} -gt 0 ]; then local chosen_project="${filtered_projects[$selected]}" if [[ "$chosen_project" == "← Retour au menu principal" ]]; then return 1 else echo -e "\n${BLUE}Configuration du projet: $chosen_project${NC}" if gcloud config set project "$chosen_project" &>/dev/null; then CURRENT_PROJECT="$chosen_project" echo -e "${GREEN}Projet configuré avec succès!${NC}" sleep 2 return 0 else echo -e "${RED}Erreur lors de la configuration du projet.${NC}" read -p "Appuyez sur Entrée pour continuer..." return 1 fi fi fi ;; $'\177'|$'\b') # Backspace if [ ${#filter} -gt 0 ]; then filter="${filter%?}" filter_projects fi ;; $'\e') # Escape return 1 ;; *) # Caractère normal if [[ "$key" =~ [a-zA-Z0-9-] ]]; then filter="$filter$key" filter_projects fi ;; esac done } # Fonction pour lister et sélectionner un projet (version simplifiée) select_project() { select_project_interactive } # Fonction pour afficher les informations de débogage des Cloud Functions show_functions_debug_info() { clear echo -e "${BLUE}${BOLD}=== Débogage Cloud Functions ===${NC}\n" echo -e "${YELLOW}1. Test Cloud Functions Gen1 (toutes régions):${NC}" gcloud functions list 2>&1 || echo "Erreur lors de la récupération des fonctions Gen1" echo "" echo -e "${YELLOW}2. Test Cloud Functions Gen2 (Cloud Run):${NC}" gcloud run services list 2>&1 || echo "Erreur lors de la récupération des services Cloud Run" echo "" echo -e "${YELLOW}3. Régions disponibles pour Cloud Functions:${NC}" gcloud functions regions list 2>&1 || echo "Erreur lors de la récupération des régions" echo "" echo -e "${YELLOW}4. Configuration actuelle:${NC}" echo "Projet: $(gcloud config get-value project 2>/dev/null)" echo "Région par défaut: $(gcloud config get-value functions/region 2>/dev/null || echo 'Non définie')" echo "" echo -e "${YELLOW}5. APIs activées:${NC}" gcloud services list --enabled --filter="name:cloudfunctions OR name:run OR name:cloudbuild" 2>&1 || echo "Erreur lors de la vérification des APIs" echo "" } # Fonction pour sélectionner une région de manière interactive avec filtrage select_region_interactive() { echo -e "\n${BLUE}Récupération des régions disponibles...${NC}" # Récupérer toutes les régions disponibles local all_regions=() while IFS= read -r region; do if [[ -n "$region" ]]; then all_regions+=("$region") fi done < <(gcloud functions regions list --format="value(name)" 2>/dev/null | sort) if [ ${#all_regions[@]} -eq 0 ]; then echo -e "${RED}Impossible de récupérer la liste des régions.${NC}" read -p "Appuyez sur Entrée pour continuer..." return 1 fi # Ajouter option de retour all_regions+=("← Retour au menu précédent") local selected=0 local filter="" local filtered_regions=() # Fonction pour filtrer les régions filter_regions() { filtered_regions=() for region in "${all_regions[@]}"; do if [[ "$region" == *"$filter"* ]]; then filtered_regions+=("$region") fi done # Réajuster la sélection si nécessaire if [ $selected -ge ${#filtered_regions[@]} ]; then selected=0 fi } # Initialiser le filtre filter_regions while true; do clear echo -e "${BLUE}${BOLD}=== Sélection de région ===${NC}\n" echo -e "${YELLOW}Configuration actuelle:${NC}" echo "Région par défaut: $(gcloud config get-value functions/region 2>/dev/null || echo 'Non définie')" echo "" echo -e "${YELLOW}Tapez pour filtrer, utilisez ↑↓ pour naviguer, Entrée pour sélectionner:${NC}" echo -e "Filtre: ${BOLD}$filter${NC}" echo "" # Afficher les régions filtrées if [ ${#filtered_regions[@]} -eq 0 ]; then echo -e "${RED}Aucune région trouvée pour le filtre '$filter'${NC}" else for i in "${!filtered_regions[@]}"; do if [ $i -eq $selected ]; then echo -e "${GREEN}► ${filtered_regions[$i]}${NC}" else echo -e " ${filtered_regions[$i]}" fi done fi echo -e "\n${BLUE}Commandes: [Backspace] Effacer filtre | [Esc] Annuler${NC}" # Lire une seule touche read -rsn1 key case $key in $'\033') # Séquence d'échappement read -rsn2 key case $key in '[A') # Flèche haut if [ ${#filtered_regions[@]} -gt 0 ]; then ((selected--)) if [ $selected -lt 0 ]; then selected=$((${#filtered_regions[@]}-1)) fi fi ;; '[B') # Flèche bas if [ ${#filtered_regions[@]} -gt 0 ]; then ((selected++)) if [ $selected -ge ${#filtered_regions[@]} ]; then selected=0 fi fi ;; esac ;; '') # Entrée if [ ${#filtered_regions[@]} -gt 0 ]; then local chosen_region="${filtered_regions[$selected]}" if [[ "$chosen_region" == "← Retour au menu précédent" ]]; then return 1 else echo -e "\n${BLUE}Configuration de la région $chosen_region...${NC}" if gcloud config set functions/region "$chosen_region" 2>/dev/null; then echo -e "${GREEN}✓ Région configurée: $chosen_region${NC}" echo -e "\n${BLUE}Nouvelle tentative de récupération des fonctions...${NC}" sleep 2 return 0 else echo -e "${RED}✗ Erreur lors de la configuration de la région${NC}" read -p "Appuyez sur Entrée pour continuer..." return 1 fi fi fi ;; $'\177'|$'\b') # Backspace if [ ${#filter} -gt 0 ]; then filter="${filter%?}" filter_regions fi ;; $'\e') # Escape return 1 ;; *) # Caractère normal if [[ "$key" =~ [a-zA-Z0-9-] ]]; then filter="$filter$key" filter_regions fi ;; esac done } # Fonction pour spécifier une région et réessayer (version simplifiée) specify_region_and_retry() { if select_region_interactive; then delete_all_functions fi } # Fonction pour supprimer toutes les Cloud Functions delete_all_functions() { # Ne pas clear ici pour garder les informations du menu principal visible echo -e "${BLUE}Récupération des Cloud Functions du projet $CURRENT_PROJECT...${NC}" # Obtenir toutes les fonctions (sans distinction Gen1/Gen2) local all_functions=() local function_names=() local function_regions=() echo -e "\n${YELLOW}Recherche de toutes les Cloud Functions...${NC}" # Récupérer tous les noms de fonctions avec leurs régions while read -r line; do if [[ -n "$line" && "$line" != *"NAME"* ]]; then # Extraire le nom et la région de la fonction name=$(echo "$line" | awk '{print $1}') region=$(echo "$line" | awk '{print $4}') if [[ -n "$name" && "$name" != "NAME" && -n "$region" ]]; then function_names+=("$name") function_regions+=("$region") all_functions+=("$name ($region)") fi fi done < <(gcloud functions list --format="table(name,state,trigger,region)" 2>/dev/null | tail -n +2) echo -e "${GREEN}Total des fonctions trouvées: ${#function_names[@]}${NC}\n" if [ ${#function_names[@]} -eq 0 ]; then echo -e "${YELLOW}Aucune Cloud Function trouvée dans le projet $CURRENT_PROJECT.${NC}" echo -e "${YELLOW}Cela peut être dû à:${NC}" echo -e " • Aucune fonction déployée" echo -e " • Fonctions dans une région non configurée" echo -e " • APIs Cloud Functions/Cloud Run non activées" echo -e " • Permissions insuffisantes" echo "" local debug_options=("Afficher les informations de débogage" "Spécifier une région" "← Retour au menu principal") echo "Que souhaitez-vous faire ?\n" show_menu "${debug_options[@]}" local debug_choice=$? case $debug_choice in 0) # Afficher debug show_functions_debug_info read -p "Appuyez sur Entrée pour continuer..." ;; 1) # Spécifier région specify_region_and_retry ;; 2) # Retour return ;; esac return fi echo -e "\n${YELLOW}${BOLD}Fonctions trouvées (${#function_names[@]}):${NC}" for func in "${function_names[@]}"; do echo -e " • $func" done echo -e "\n${RED}${BOLD}⚠️ ATTENTION: Cette action supprimera TOUTES les Cloud Functions du projet!${NC}" echo -e "${RED}Cette action est IRRÉVERSIBLE!${NC}\n" local confirm_options=("Oui, supprimer toutes les fonctions" "Non, annuler") show_menu "${confirm_options[@]}" local confirm=$? if [ $confirm -eq 0 ]; then echo -e "\n${RED}Suppression en cours...${NC}\n" local success_count=0 local error_count=0 # Supprimer toutes les fonctions avec leur région spécifique for i in "${!function_names[@]}"; do local func="${function_names[$i]}" local region="${function_regions[$i]}" echo -e "Suppression de: ${BOLD}$func${NC} (région: $region)" # Capturer l'erreur détaillée avec la région spécifique local error_output error_output=$(gcloud functions delete "$func" --region="$region" --quiet 2>&1) local exit_code=$? if [ $exit_code -eq 0 ]; then echo -e "${GREEN}✓ $func supprimée${NC}" ((success_count++)) else echo -e "${RED}✗ Erreur lors de la suppression de $func${NC}" echo -e "${RED} Détail: $error_output${NC}" ((error_count++)) fi # Petite pause pour éviter les erreurs de rate limiting sleep 0.5 done echo -e "\n${BOLD}Résumé:${NC}" echo -e "${GREEN}• Fonctions supprimées: $success_count${NC}" if [ $error_count -gt 0 ]; then echo -e "${RED}• Erreurs: $error_count${NC}" echo -e "${YELLOW}Il y a eu des erreurs lors de la suppression.${NC}" echo -e "${YELLOW}Vérifiez les permissions et l'état des fonctions.${NC}" echo -e "${YELLOW}Les erreurs détaillées sont affichées ci-dessus.${NC}" else echo -e "${GREEN}Toutes les fonctions ont été supprimées avec succès!${NC}" fi echo -e "\n${BLUE}Appuyez sur Entrée pour continuer...${NC}" read -r else echo -e "\n${YELLOW}Suppression annulée.${NC}" echo -e "\n${BLUE}Appuyez sur Entrée pour continuer...${NC}" read -r fi read -p "Appuyez sur Entrée pour continuer..." } # Fonction principale main() { clear check_gcloud while true; do get_current_project local main_options=() if [ "$CURRENT_PROJECT" != "Aucun" ]; then main_options=("Supprimer toutes les Cloud Functions" "Changer de projet" "Se connecter à GCP" "Quitter") else main_options=("Changer de projet" "Se connecter à GCP" "Quitter") fi show_menu "${main_options[@]}" local choice=$? if [ "$CURRENT_PROJECT" != "Aucun" ]; then case $choice in 0) # Supprimer toutes les fonctions delete_all_functions ;; 1) # Changer de projet select_project ;; 2) # Se connecter à GCP handle_authentication ;; 3) # Quitter echo -e "\n${YELLOW}Au revoir!${NC}" exit 0 ;; esac else case $choice in 0) # Changer de projet select_project ;; 1) # Se connecter à GCP handle_authentication ;; 2) # Quitter echo -e "\n${YELLOW}Au revoir!${NC}" exit 0 ;; esac fi done } # Gestion des signaux pour un arrêt propre trap 'echo -e "\n${YELLOW}Script interrompu.${NC}"; exit 0' INT TERM # Lancement du script main