From 94e786a0ab960a238944ad29a4dc7ff96cbdf689 Mon Sep 17 00:00:00 2001 From: Tellsanguis Date: Thu, 27 Nov 2025 19:07:54 +0100 Subject: [PATCH] =?UTF-8?q?chore:=20D=C3=A9placer=20script=20DRBD=20vers?= =?UTF-8?q?=20cicd=5Fbackup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le script n'est plus nécessaire car le provider Proxmox clone correctement le disque du template avec disk_gb. Conservé dans cicd_backup pour référence future. --- scripts/manage_linstor_resources.py | 403 ---------------------------- 1 file changed, 403 deletions(-) delete mode 100644 scripts/manage_linstor_resources.py diff --git a/scripts/manage_linstor_resources.py b/scripts/manage_linstor_resources.py deleted file mode 100644 index 214820d..0000000 --- a/scripts/manage_linstor_resources.py +++ /dev/null @@ -1,403 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Script de gestion des ressources DRBD Linstor pour les VMs K3s -Exécuté avant le déploiement Terraform pour s'assurer que les ressources -de stockage DRBD sont créées et dimensionnées correctement. -""" - -import subprocess -import sys -import json -import argparse -import os -from typing import Dict, Optional, Tuple - - -# Clé SSH globale (peut être définie via variable d'environnement) -SSH_KEY_PATH = os.environ.get("SSH_KEY_PATH", None) - -# Noms de ressources DRBD pour chaque VM -# Format attendu par Proxmox: vm-{VMID}-disk-0 -RESOURCE_NAMES = { - 1000: "vm-1000-disk-0", # acemagician - k3s-server-1 - 1001: "vm-1001-disk-0", # elitedesk - k3s-server-2 -} - -# Configuration des nœuds Proxmox -NODE_CONFIG = { - 1000: {"node": "acemagician", "vm_name": "k3s-server-1"}, - 1001: {"node": "elitedesk", "vm_name": "k3s-server-2"}, -} - - -def run_ssh_command(command: str, host: str = "192.168.100.30", ssh_key: Optional[str] = None) -> Tuple[int, str, str]: - """ - Exécute une commande SSH sur le contrôleur Linstor (thinkpad - 192.168.100.30). - - Args: - command: Commande à exécuter - host: Hôte sur lequel exécuter la commande (défaut: 192.168.100.30) - ssh_key: Chemin vers la clé SSH privée (optionnel) - - Returns: - Tuple (code_retour, stdout, stderr) - """ - ssh_cmd = ["ssh", "-o", "StrictHostKeyChecking=no"] - - # Ajouter la clé SSH si spécifiée - if ssh_key: - ssh_cmd.extend(["-i", ssh_key]) - - ssh_cmd.extend([f"root@{host}", command]) - - try: - result = subprocess.run( - ssh_cmd, - capture_output=True, - text=True, - timeout=30 - ) - return result.returncode, result.stdout, result.stderr - except subprocess.TimeoutExpired: - return 1, "", "Timeout lors de l'exécution de la commande SSH" - except Exception as e: - return 1, "", f"Erreur lors de l'exécution SSH: {str(e)}" - - -def check_resource_exists(resource_name: str, ssh_key: Optional[str] = None) -> bool: - """ - Vérifie si une ressource DRBD existe. - - Args: - resource_name: Nom de la ressource à vérifier - ssh_key: Chemin vers la clé SSH privée (optionnel) - - Returns: - True si la ressource existe, False sinon - """ - # Méthode 1: Vérifier avec resource-definition list - returncode, stdout, stderr = run_ssh_command( - f"linstor resource-definition list", - ssh_key=ssh_key - ) - - if returncode == 0: - # Cherche le nom exact de la ressource dans la sortie - # Format typique: "| pm-a7f3c8e1 | ..." - lines = stdout.strip().split('\n') - for line in lines: - # Ignore les lignes d'en-tête et de séparation - if line.startswith('+-') or line.startswith('| ResourceName'): - continue - # Cherche la ressource dans les lignes de données - if f"| {resource_name} " in line or f"|{resource_name}|" in line: - print(f" → Ressource trouvée dans la liste des définitions") - return True - - # Méthode 2: Vérifier avec volume-definition (si resource-definition existe, volume existe aussi) - returncode, stdout, stderr = run_ssh_command( - f"linstor volume-definition list --resource {resource_name}", - ssh_key=ssh_key - ) - - if returncode == 0 and stdout.strip() and "VolumeNr" in stdout: - print(f" → Volume trouvé pour la ressource") - return True - - print(f" → Ressource non trouvée") - return False - - -def get_resource_size(resource_name: str, ssh_key: Optional[str] = None) -> Optional[int]: - """ - Récupère la taille actuelle d'une ressource DRBD en GiB. - - Args: - resource_name: Nom de la ressource - ssh_key: Chemin vers la clé SSH privée (optionnel) - - Returns: - Taille en GiB ou None si erreur - """ - # Essayer d'abord avec machine-readable (JSON) - returncode, stdout, stderr = run_ssh_command( - f"linstor volume-definition list --resource {resource_name} --machine-readable", - ssh_key=ssh_key - ) - - if returncode == 0 and stdout.strip(): - try: - # Parse la sortie JSON de Linstor - data = json.loads(stdout) - if data and len(data) > 0: - volume_defs = data[0].get("volume_definitions", []) - if volume_defs and len(volume_defs) > 0: - # Taille en KiB, conversion en GiB - size_kib = volume_defs[0].get("size_kib", 0) - size_gib = size_kib // (1024 * 1024) - print(f" → Taille récupérée via JSON: {size_gib}GiB") - return size_gib - except (json.JSONDecodeError, KeyError, IndexError) as e: - print(f" ⚠ Erreur parsing JSON, essai avec format texte: {e}") - - # Fallback: parser la sortie texte normale - returncode, stdout, stderr = run_ssh_command( - f"linstor volume-definition list --resource {resource_name}", - ssh_key=ssh_key - ) - - if returncode == 0 and stdout.strip(): - # Format typique: - # | VolumeNr | ... | Size | - # | 0 | ... | 100.00 GiB | - lines = stdout.strip().split('\n') - for line in lines: - if '|' in line and 'GiB' in line and not line.startswith('| VolumeNr'): - # Extrait la taille en GiB - parts = [p.strip() for p in line.split('|')] - for part in parts: - if 'GiB' in part: - try: - size_str = part.replace('GiB', '').strip() - size_gib = int(float(size_str)) - print(f" → Taille récupérée via texte: {size_gib}GiB") - return size_gib - except ValueError: - continue - - print(f" ⚠ Impossible de récupérer la taille, sortie: {stdout[:200]}") - return None - - -def create_resource(resource_name: str, size_gib: int, nodes: list, ssh_key: Optional[str] = None) -> bool: - """ - Crée une nouvelle ressource DRBD avec réplication. - - Args: - resource_name: Nom de la ressource à créer - size_gib: Taille en GiB - nodes: Liste des nœuds pour la réplication - ssh_key: Chemin vers la clé SSH privée (optionnel) - - Returns: - True si succès, False sinon - """ - print(f"Création de la ressource {resource_name} avec {size_gib}GiB...") - - # Étape 1: Créer la définition de ressource - print(f" [1/3] Création de la définition de ressource...") - returncode, stdout, stderr = run_ssh_command( - f"linstor resource-definition create {resource_name}", - ssh_key=ssh_key - ) - - if returncode != 0: - # Si la ressource existe déjà, ce n'est pas une erreur fatale - if "already exists" in stdout or "already exists" in stderr: - print(f" ⚠ La définition de ressource existe déjà, passage à l'étape suivante") - else: - print(f"Erreur lors de la création de la définition: {stderr}", file=sys.stderr) - if stdout: - print(f"Sortie standard: {stdout}", file=sys.stderr) - return False - else: - print(f" ✓ Définition de ressource créée") - - # Étape 2: Créer la définition de volume - print(f" [2/3] Création de la définition de volume...") - returncode, stdout, stderr = run_ssh_command( - f"linstor volume-definition create {resource_name} {size_gib}GiB", - ssh_key=ssh_key - ) - - if returncode != 0: - # Si le volume existe déjà, ce n'est pas une erreur fatale - if "already exists" in stdout or "already exists" in stderr: - print(f" ⚠ La définition de volume existe déjà, passage à l'étape suivante") - else: - print(f"Erreur lors de la création du volume: {stderr}", file=sys.stderr) - if stdout: - print(f"Sortie standard: {stdout}", file=sys.stderr) - return False - else: - print(f" ✓ Définition de volume créée") - - # Étape 3: Déployer la ressource sur les nœuds avec réplication - print(f" [3/3] Déploiement de la ressource sur les nœuds...") - deployed_count = 0 - for node in nodes: - print(f" → Déploiement sur {node}...") - returncode, stdout, stderr = run_ssh_command( - f"linstor resource create {node} {resource_name} --storage-pool linstor_storage --resource-group pve-rg", - ssh_key=ssh_key - ) - - if returncode != 0: - # Si la ressource existe déjà sur ce nœud, ce n'est pas une erreur - if "already exists" in stdout or "already exists" in stderr or "already deployed" in stdout: - print(f" ⚠ Ressource déjà déployée sur {node}") - deployed_count += 1 - else: - print(f"Erreur lors du déploiement sur {node}: {stderr}", file=sys.stderr) - if stdout: - print(f"Sortie standard: {stdout}", file=sys.stderr) - # Continue avec les autres nœuds même en cas d'erreur - continue - else: - print(f" ✓ Ressource déployée sur {node}") - deployed_count += 1 - - # Affiche le résumé du déploiement - print(f"✓ Ressource {resource_name} déployée sur {deployed_count}/{len(nodes)} nœuds") - return True - - -def resize_resource(resource_name: str, new_size_gib: int, ssh_key: Optional[str] = None) -> bool: - """ - Augmente la taille d'une ressource DRBD existante. - - Args: - resource_name: Nom de la ressource à redimensionner - new_size_gib: Nouvelle taille en GiB - ssh_key: Chemin vers la clé SSH privée (optionnel) - - Returns: - True si succès, False sinon - """ - print(f"Redimensionnement de la ressource {resource_name} à {new_size_gib}GiB...") - - returncode, stdout, stderr = run_ssh_command( - f"linstor volume-definition set-size {resource_name} 0 {new_size_gib}GiB", - ssh_key=ssh_key - ) - - if returncode != 0: - print(f"Erreur lors du redimensionnement: {stderr}", file=sys.stderr) - return False - - print(f"✓ Ressource {resource_name} redimensionnée avec succès") - return True - - -def manage_vm_resource(vmid: int, size_gib: int, dry_run: bool = False, ssh_key: Optional[str] = None) -> bool: - """ - Gère la ressource DRBD pour une VM spécifique. - - Args: - vmid: ID de la VM - size_gib: Taille souhaitée en GiB - dry_run: Si True, affiche les actions sans les exécuter - ssh_key: Chemin vers la clé SSH privée (optionnel) - - Returns: - True si succès, False sinon - """ - if vmid not in RESOURCE_NAMES: - print(f"VMID {vmid} non configuré", file=sys.stderr) - return False - - resource_name = RESOURCE_NAMES[vmid] - node_info = NODE_CONFIG[vmid] - - print(f"\n{'='*60}") - print(f"Gestion de la ressource pour VM {vmid} ({node_info['vm_name']})") - print(f"Ressource DRBD: {resource_name}") - print(f"Nœud Proxmox: {node_info['node']}") - print(f"Taille souhaitée: {size_gib}GiB") - print(f"{'='*60}\n") - - # Vérifie si la ressource existe - resource_exists = check_resource_exists(resource_name, ssh_key=ssh_key) - - if not resource_exists: - print(f"La ressource {resource_name} n'existe pas.") - - if dry_run: - print(f"[DRY-RUN] Créerait la ressource {resource_name} avec {size_gib}GiB") - return True - - # Créer la ressource sur les 2 nœuds avec stockage (thinkpad = contrôleur uniquement) - nodes = ["acemagician", "elitedesk"] - return create_resource(resource_name, size_gib, nodes, ssh_key=ssh_key) - - else: - print(f"La ressource {resource_name} existe déjà.") - - # Vérifie la taille actuelle - current_size = get_resource_size(resource_name, ssh_key=ssh_key) - - if current_size is None: - print("⚠ Impossible de récupérer la taille actuelle") - print("La ressource existe mais le volume peut ne pas être complètement configuré") - print("Tentative de création/configuration du volume...") - - if dry_run: - print(f"[DRY-RUN] Tenterait de créer/configurer le volume avec {size_gib}GiB") - return True - - # Tente de créer le volume (sera ignoré s'il existe déjà) - nodes = ["acemagician", "elitedesk"] - return create_resource(resource_name, size_gib, nodes, ssh_key=ssh_key) - - print(f"Taille actuelle: {current_size}GiB") - - if current_size == size_gib: - print(f"✓ La taille correspond déjà ({size_gib}GiB), aucune action nécessaire") - return True - - elif current_size < size_gib: - print(f"La taille doit être augmentée de {current_size}GiB à {size_gib}GiB") - - if dry_run: - print(f"[DRY-RUN] Redimensionnerait {resource_name} à {size_gib}GiB") - return True - - return resize_resource(resource_name, size_gib, ssh_key=ssh_key) - - else: - print(f"⚠ La taille actuelle ({current_size}GiB) est supérieure à la taille souhaitée ({size_gib}GiB)") - print("La réduction de taille n'est pas supportée, conservation de la taille actuelle") - return True - - -def main(): - """Point d'entrée principal du script.""" - parser = argparse.ArgumentParser( - description="Gestion des ressources DRBD Linstor pour les VMs K3s" - ) - parser.add_argument( - "--vmid", - type=int, - required=True, - choices=[1000, 1001], - help="ID de la VM (1000=acemagician, 1001=elitedesk)" - ) - parser.add_argument( - "--size", - type=int, - required=True, - help="Taille du disque en GiB" - ) - parser.add_argument( - "--dry-run", - action="store_true", - help="Affiche les actions sans les exécuter" - ) - parser.add_argument( - "--ssh-key", - type=str, - default=SSH_KEY_PATH, - help="Chemin vers la clé SSH privée (défaut: variable d'environnement SSH_KEY_PATH)" - ) - - args = parser.parse_args() - - # Exécute la gestion de la ressource - success = manage_vm_resource(args.vmid, args.size, args.dry_run, ssh_key=args.ssh_key) - - sys.exit(0 if success else 1) - - -if __name__ == "__main__": - main()