Files
ship2net-www/generer_relais_live.php

149 lines
6.4 KiB
PHP

<?php
// ============================================================================
// generer_relais_live.php - Génération des relais Traefik du Live distant, un par bateau (synthèse §49, étape 2f).
// Exécuté NATIVEMENT sur le VPS, de façon planifiée (ship2net-relais-live.timer) ou à la main :
// /usr/bin/php /var/www/generer_relais_live.php
//
// Pour chaque bateau valide dont le module affecté (affectation active) a une adresse NetBird connue
// (TB_Cartes.Adresse_netbird), écrit /opt/netbird/dynamic/bateau-<N>.yml : https://b<N>.ship2net.fr relayé vers ce
// module, avec ouverture de session (/_auth) et vérification de la session à chaque requête (ForwardAuth) - cf
// live-commun.yml. Supprime les relais des bateaux qui ne remplissent plus ces conditions (bateau dévalidé,
// affectation clôturée, adresse retirée).
//
// Ajouter un bateau au Live ne demande donc rien d'autre que son affectation (lot 4) : ni DNS, ni certificat
// (certificat générique *.ship2net.fr), ni fichier à écrire à la main. Une réaffectation de module change la
// destination du relais, pas l'adresse du bateau.
//
// Principes :
// - seuls les fichiers "bateau-<N>.yml" sont gérés : aucun autre fichier du dossier n'est jamais touché ;
// - un fichier n'est réécrit que si son contenu change (Traefik recharge sa configuration à chaque écriture) ;
// - écriture atomique (fichier temporaire puis renommage) : Traefik ne lit jamais un fichier à moitié écrit ;
// - l'adresse NetBird est validée (adresse IPv4 stricte) avant d'être écrite dans la configuration de Traefik.
// ============================================================================
chdir("/var/www/html");
require_once __DIR__ . "/config/config.php";
require_once __DIR__ . "/config/fonctions_bdd.php";
const REPERTOIRE_RELAIS = "/opt/netbird/dynamic";
const MOTIF_FICHIER_RELAIS = '/^bateau-([1-9][0-9]*)\.yml$/';
// ----------------------------------------------------------------------------
// Contenu du fichier de relais d'un bateau (modèle validé sur le bateau 1, étape 2d).
// ----------------------------------------------------------------------------
function Contenu_relais($id_bateau, $adresse_netbird)
{
$hote = "b".$id_bateau.".".URL_SITE;
return <<<YAML
# ============================================================================
# Live distant du bateau {$id_bateau} - https://{$hote} (synthèse §49)
# FICHIER GÉNÉRÉ AUTOMATIQUEMENT par /var/www/generer_relais_live.php - ne pas modifier à la main
# (il serait réécrit au passage suivant). Module affecté : {$adresse_netbird}
# ============================================================================
http:
routers:
bateau-{$id_bateau}-auth:
rule: "Host(`{$hote}`) && Path(`/_auth`)"
priority: 1000
entrypoints:
- websecure
tls:
certResolver: ovh
domains:
- main: "*.ship2net.fr"
middlewares:
- live-auth-chemin@file
service: live-auth@file
bateau-{$id_bateau}:
rule: "Host(`{$hote}`)"
entrypoints:
- websecure
tls:
certResolver: ovh
domains:
- main: "*.ship2net.fr"
middlewares:
- live-verification@file
service: bateau-{$id_bateau}
services:
bateau-{$id_bateau}:
loadBalancer:
servers:
- url: "http://{$adresse_netbird}:80"
YAML;
}
// ----------------------------------------------------------------------------
// Écriture atomique : fichier temporaire (extension non lue par Traefik) puis renommage.
// ----------------------------------------------------------------------------
function Ecrire_atomique($chemin, $contenu)
{
$temporaire = $chemin.".tmp";
if (file_put_contents($temporaire, $contenu) === false) return false;
chmod($temporaire, 0644);
return rename($temporaire, $chemin);
}
function Generer_relais_live()
{
if (!is_dir(REPERTOIRE_RELAIS) || !is_writable(REPERTOIRE_RELAIS))
{
echo "ERREUR : répertoire ".REPERTOIRE_RELAIS." absent ou non accessible en écriture.\n";
return 1;
}
Ouverture_bdd("127.0.0.1:3307", BDD_USER, BDD_PASSWORD, BDD_DATABASE);
$db = $_SESSION['db'];
// Bateaux éligibles : valides, avec une affectation active vers un module dont l'adresse NetBird est connue.
$requete = "SELECT B.Cle_primaire, C.Adresse_netbird
FROM TB_Bateaux B
JOIN TB_Affectations_bateaux A ON A.ID_Bateau = B.Cle_primaire AND A.Date_fin IS NULL
JOIN TB_Cartes C ON C.Adresse_mac = A.Adresse_mac
WHERE B.Validite = 1 AND C.Adresse_netbird IS NOT NULL AND C.Adresse_netbird <> ''";
$resultat = $db->query($requete);
$attendus = array();
while ($ligne = $resultat->fetch_assoc())
{
$adresse = trim($ligne['Adresse_netbird']);
if (filter_var($adresse, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false)
{
echo " ! bateau {$ligne['Cle_primaire']} : adresse NetBird '{$adresse}' invalide - relais non généré.\n";
continue;
}
$attendus["bateau-".(int)$ligne['Cle_primaire'].".yml"] = Contenu_relais((int)$ligne['Cle_primaire'], $adresse);
}
$resultat->free();
Fermeture_bdd();
$nb_crees = $nb_modifies = $nb_supprimes = $nb_inchanges = 0;
// Création / mise à jour :
foreach ($attendus as $nom => $contenu)
{
$chemin = REPERTOIRE_RELAIS."/".$nom;
$existant = is_file($chemin) ? file_get_contents($chemin) : null;
if ($existant === $contenu) { $nb_inchanges++; continue; }
if (!Ecrire_atomique($chemin, $contenu)) { echo " ! écriture impossible : {$chemin}\n"; continue; }
if ($existant === null) { $nb_crees++; echo " + {$nom} créé\n"; }
else { $nb_modifies++; echo " ~ {$nom} mis à jour\n"; }
}
// Suppression des relais qui ne correspondent plus à un bateau éligible (fichiers "bateau-<N>.yml" seulement) :
foreach (scandir(REPERTOIRE_RELAIS) as $nom)
{
if (preg_match(MOTIF_FICHIER_RELAIS, $nom) !== 1 || isset($attendus[$nom])) continue;
if (unlink(REPERTOIRE_RELAIS."/".$nom)) { $nb_supprimes++; echo " - {$nom} supprimé\n"; }
else echo " ! suppression impossible : {$nom}\n";
}
echo count($attendus)." bateau(x) éligible(s) : {$nb_crees} créé(s), {$nb_modifies} mis à jour, {$nb_supprimes} supprimé(s), {$nb_inchanges} inchangé(s).\n";
return 0;
}
exit(Generer_relais_live());