requete()->post($this->url('/stacks'), [ 'stack_name' => $nom, 'disable_rollback' => true, 'template' => $template, ]); if ($reponse->failed()) { throw new RuntimeException("Heat a refusé la création de la stack {$nom} : ".$reponse->body()); } return ['id' => $reponse->json('stack.id')]; } /** * @return array{statut: string, raison: ?string, sorties: array} */ public function etatStack(string $nom, string $id): array { $reponse = $this->requete()->get($this->url("/stacks/{$nom}/{$id}")); if ($reponse->failed()) { throw new RuntimeException("Impossible de lire l'état de la stack {$nom} : ".$reponse->body()); } $sorties = []; foreach ($reponse->json('stack.outputs') ?? [] as $sortie) { $sorties[$sortie['output_key']] = $sortie['output_value']; } return [ 'statut' => $reponse->json('stack.stack_status'), 'raison' => $reponse->json('stack.stack_status_reason'), 'sorties' => $sorties, ]; } public function supprimerStack(string $nom, string $id): void { $reponse = $this->requete()->delete($this->url("/stacks/{$nom}/{$id}")); // 404 : déjà supprimée (idempotent, pas une erreur pour nous). if ($reponse->failed() && $reponse->status() !== 404) { throw new RuntimeException("Heat a refusé la suppression de la stack {$nom} : ".$reponse->body()); } } private function requete() { return Http::withHeaders(['X-Auth-Token' => $this->auth->jeton()]); } private function url(string $chemin): string { return config('openstack.heat_url').'/'.$this->auth->projetId().$chemin; } }