# Analyse de `infrastructure/prometheus.go` ## Ce que fait le fichier Ce fichier implémente un service de monitoring qui interroge une instance **Prometheus** pour collecter des métriques de conteneurs Kubernetes associés à une réservation (Booking). ### Structures de données | Struct | Role | |---|---| | `MetricsSnapshot` | Snapshot de métriques associé à une origine (source). **Note : cette struct locale est déclarée mais jamais utilisée** — le code utilise en réalité `models.MetricsSnapshot` de oc-lib. | | `Metric` | Paire nom/valeur d'une métrique. **Même remarque** — le code utilise `models.Metric`. | | `PrometheusResponse` | Mapping de la réponse JSON de l'API Prometheus `/api/v1/query`. | ### Métriques collectées (`queriesMetrics`) | # | Requête PromQL | Mesure | |---|---|---| | 1 | `rate(container_cpu_usage_seconds_total{namespace}[1m]) * 100` | Utilisation CPU (%) | | 2 | `container_memory_usage_bytes{namespace}` | Mémoire utilisée (bytes) | | 3 | `container_fs_usage_bytes / container_fs_limit_bytes * 100` | Utilisation disque (%) | | 4 | `DCGM_FI_DEV_GPU_UTIL{namespace}` | Utilisation GPU (NVIDIA DCGM) | | 5 | `rate(container_fs_reads_bytes_total[1m])` | Débit lecture disque (bytes/s) | | 6 | `rate(container_fs_writes_bytes_total[1m])` | Débit écriture disque (bytes/s) | | 7 | `rate(container_network_receive_bytes_total[1m])` | Bande passante réseau entrante (bytes/s) | | 8 | `rate(container_network_transmit_bytes_total[1m])` | Bande passante réseau sortante (bytes/s) | | 9 | `rate(http_requests_total[1m])` | Requêtes HTTP/s | | 10 | `rate(http_requests_total{status=~"5.."}[1m]) / rate(http_requests_total[1m]) * 100` | Taux d'erreur HTTP 5xx (%) | Métriques commentées (non actives) : `system_load_average`, `system_network_latency_ms`, `app_mean_time_to_repair_seconds`, `app_mean_time_between_failure_seconds`. ### Méthodes #### `queryPrometheus(promURL, expr, namespace) Metric` - Construit une requête GET vers `/api/v1/query` de Prometheus. - Injecte le namespace dans l'expression PromQL via `fmt.Sprintf`. - Parse la réponse JSON et extrait la première valeur du premier résultat. - Retourne `-1` si aucun résultat. #### `Call(book, user, peerID, groups) (Booking, map[string]MetricsSnapshot)` - Charge la ressource de calcul (`ComputeResource`) liée au booking. - Pour chaque instance de la ressource, cherche le `LiveDatacenter` correspondant. - Lance en **goroutine** (parallèle) l'exécution de toutes les requêtes PromQL pour chaque datacenter ayant un `MonitorPath`. - Attend toutes les goroutines (`sync.WaitGroup`), puis retourne les métriques groupées par instance. #### `Stream(bookingID, interval, user, peerID, groups, websocket)` - Boucle de monitoring en continu jusqu'à `ExpectedEndDate` du booking ou signal de kill. - A chaque tick (`interval`), appelle `Call()` dans une goroutine. - Envoie les métriques en temps réel via **WebSocket**. - Accumule les métriques en mémoire et les persiste dans le booking tous les `max` (100) cycles. - Supporte un mécanisme de kill via la variable globale `Kill`. --- ## Problemes et points d'attention ### Bugs potentiels 1. **Race condition dans `Stream`** — Les variables `mets`, `bookIDS`, `book` sont partagées entre la boucle principale et les goroutines lancées à chaque tick, **sans synchronisation** (pas de mutex). Si `interval` est court, plusieurs goroutines peuvent écrire simultanément dans `mets` et `bookIDS`. 2. **Race condition sur `Kill`** — La variable globale `Kill` est lue dans la boucle sans verrouiller `LockKill`. Le mutex n'est utilisé que pour l'écriture. 3. **Structs locales inutilisées** — `MetricsSnapshot` et `Metric` (lignes 22-31) sont déclarées localement mais le code utilise `models.MetricsSnapshot` et `models.Metric`. Code mort à nettoyer. 4. **Requête PromQL avec double placeholder** — La requête filesystem (ligne 47) contient deux `%s` mais `queryPrometheus` ne fait qu'un seul `fmt.Sprintf(expr, namespace)`. Cela provoque un **`%!s(MISSING)`** dans la requête. Il faut passer le namespace deux fois ou réécrire la fonction. 5. **Pas de timeout HTTP** — `http.Get()` utilise le client par défaut sans timeout. Un Prometheus lent peut bloquer indéfiniment. 6. **Pas de gestion d'erreur sur `WriteJSON`** — Si le WebSocket est fermé côté client, l'écriture échoue silencieusement. ### Améliorations possibles #### Fiabilité - **Ajouter un `context.Context`** à `queryPrometheus` et `Call` pour supporter les timeouts et l'annulation. - **Utiliser un `http.Client` avec timeout** au lieu de `http.Get`. - **Protéger les accès concurrents** dans `Stream` avec un `sync.Mutex` sur `mets`/`bookIDS`. - **Remplacer la variable globale `Kill`** par un `context.WithCancel` ou un channel, plus idiomatique en Go. #### Métriques supplémentaires envisageables - `container_cpu_cfs_throttled_seconds_total` — Throttling CPU (le container est bridé). - `kube_pod_container_status_restarts_total` — Nombre de restarts (instabilité). - `container_memory_working_set_bytes` — Mémoire réelle utilisée (exclut le cache, plus précis que `memory_usage_bytes`). - `kube_pod_status_phase` — Phase du pod (Running, Pending, Failed...). - `container_oom_events_total` ou `kube_pod_container_status_last_terminated_reason` — Détection des OOM kills. - `kubelet_volume_stats_used_bytes` / `kubelet_volume_stats_capacity_bytes` — Utilisation des PVC. - `DCGM_FI_DEV_MEM_COPY_UTIL` — Utilisation mémoire GPU. - `DCGM_FI_DEV_GPU_TEMP` — Température GPU. - `node_cpu_seconds_total` / `node_memory_MemAvailable_bytes` — Métriques au niveau du noeud (vue globale). #### Architecture - **Range queries** (`/api/v1/query_range`) — Actuellement seul l'instant query est utilisé. Pour le streaming sur une période, `query_range` permettrait de récupérer des séries temporelles complètes et de calculer des moyennes/percentiles. - **Labels dans les résultats** — Actuellement seule la première série est lue (`Result[0]`). On perd l'information si plusieurs pods/containers matchent. Agréger ou renvoyer toutes les séries. - **Noms de métriques lisibles** — Mapper les expressions PromQL vers des noms humains (`cpu_usage_percent`, `memory_bytes`, etc.) au lieu de stocker l'expression brute comme nom. - **Health check Prometheus** — Ajouter une méthode pour vérifier que Prometheus est accessible (`/-/healthy`). --- ## Résumé Le fichier est **fonctionnel** pour un cas d'usage basique (collecte one-shot + streaming WebSocket), mais présente des **race conditions** dans `Stream`, un **bug sur la requête filesystem** (double `%s`), et du **code mort**. Les améliorations prioritaires sont la correction des accès concurrents et l'ajout de timeouts HTTP.