Paillasse/portail/app/Services/Labs/DefinitionLab.php
2026-10-12 21:32:52 +02:00

99 lines
3.1 KiB
PHP

<?php
namespace App\Services\Labs;
use Illuminate\Support\Facades\File;
use RuntimeException;
use Symfony\Component\Yaml\Yaml;
/**
* Lit le lab.yaml d'un lab (voir paillasse-contenus/README.md pour le
* format) : topologie pour GenerateurTemplateHeat, vérifications pour la
* correction.
*/
class DefinitionLab
{
public readonly string $identifiant;
public readonly string $titre;
public readonly ?string $niveau;
public readonly ?int $dureeMin;
/** @var array<int, array{nom: string, cidr: string}> */
public readonly array $reseaux;
/** @var array<int, array{nom: string, image: string, flavor: string, reseaux: array<int, string>, preparation: ?string}> */
public readonly array $machines;
/** @var array<int, array{id: string, titre: string, machine: string, points: int, message_echec: string, bonus: bool}> */
public readonly array $verifications;
public static function depuis(string $identifiantLab): self
{
if (! preg_match('/^[a-z0-9][a-z0-9-]*$/', $identifiantLab)) {
throw new RuntimeException("Identifiant de lab invalide : {$identifiantLab}");
}
$chemin = config('labs.dossier')."/{$identifiantLab}/lab.yaml";
if (! File::exists($chemin)) {
throw new RuntimeException("Lab introuvable : {$chemin}");
}
return new self(Yaml::parseFile($chemin));
}
/**
* @return array<int, string>
*/
public static function identifiantsDisponibles(): array
{
return collect(File::directories(config('labs.dossier')))
->map(fn (string $dossier) => basename($dossier))
->filter(fn (string $id) => File::exists(config('labs.dossier')."/{$id}/lab.yaml"))
->values()
->all();
}
public function nombreMachines(): int
{
return count($this->machines);
}
/**
* @param array<string, mixed> $donnees
*/
private function __construct(array $donnees)
{
$this->identifiant = $donnees['id'];
$this->titre = $donnees['titre'];
$this->niveau = $donnees['niveau'] ?? null;
$this->dureeMin = $donnees['duree_min'] ?? null;
$this->reseaux = $donnees['reseaux'];
$this->machines = array_map(
fn (array $m) => [
'nom' => $m['nom'],
'image' => $m['image'],
'flavor' => $m['flavor'],
'reseaux' => $m['reseaux'],
'preparation' => $m['preparation'] ?? null,
],
$donnees['machines'],
);
// Les commandes et le résultat attendu ne sont lus que par le
// correcteur, sur l'hyperviseur : le portail n'en a pas besoin.
$this->verifications = array_map(
fn (array $v) => [
'id' => $v['id'],
'titre' => $v['titre'],
'machine' => $v['machine'],
'points' => (int) ($v['points'] ?? 1),
'message_echec' => $v['message_echec'] ?? 'Vérification non réussie.',
'bonus' => str_starts_with($v['id'], 'bonus-'),
],
$donnees['verifications'] ?? [],
);
}
}