simplificaiton config

This commit is contained in:
2026-03-18 08:51:50 +01:00
parent 88b0dd4e77
commit ac6b80cb69
8 changed files with 135 additions and 193 deletions

View File

@@ -8,40 +8,36 @@
require_once __DIR__ . '/../lib/monitoring-lib.php';
// --- Configuration ---
// On s'appuie sur le chargement de la lib, mais on surcharge si nécessaire
$conf_file = "/opt/monitoring/conf/autoupdate.conf.php"; // Format PHP recommandé
// --- Chargement de la configuration spécifique ---
// Note : La lib a déjà chargé $CONFIG['UPDATE_BASE_URL'] etc. depuis monitoring.local.conf.php
// On ne charge les fichiers spécifiques que s'ils apportent des règles de mise à jour uniques.
foreach (["/opt/monitoring/conf/autoupdate.conf.php", "/opt/monitoring/conf/autoupdate.local.conf.php"] as $conf) {
if (file_exists($conf)) {
$extra_conf = include $conf;
if (is_array($extra_conf)) {
$CONFIG = array_replace_recursive($CONFIG, $extra_conf);
}
}
if (file_exists($conf)) {
$extra_conf = include $conf;
if (is_array($extra_conf)) {
$CONFIG = array_replace_recursive($CONFIG, $extra_conf);
}
}
}
// Variables par défaut
// Variables par défaut (fallback si absent de la config globale)
$UPDATE_ENABLED = $CONFIG['UPDATE_ENABLED'] ?? true;
$UPDATE_TMP_DIR = $CONFIG['UPDATE_TMP_DIR'] ?? '/tmp/monitoring-update';
$UPDATE_TIMEOUT_CONNECT = $CONFIG['UPDATE_TIMEOUT_CONNECT'] ?? 3;
$UPDATE_TIMEOUT_TOTAL = $CONFIG['UPDATE_TIMEOUT_TOTAL'] ?? 15;
$UPDATE_MANIFEST_URL = $CONFIG['UPDATE_MANIFEST_URL'] ?? '';
$UPDATE_BASE_URL = $CONFIG['UPDATE_BASE_URL'] ?? '';
$UPDATE_ALLOW_DELETE = $CONFIG['UPDATE_ALLOW_DELETE'] ?? false;
$MONITORING_BASE_DIR = $CONFIG['MONITORING_BASE_DIR'] ?? '/opt/monitoring';
$MONITORING_BASE_DIR = $MONITORING_BASE_DIR; // Provient de la lib
// --- Initialisation ---
lock_or_exit("monitoring-update");
if (!$UPDATE_ENABLED) {
log_notice("update_disabled", "Mise à jour désactivée par configuration");
log_notice("update_disabled", "Mise à jour désactivée");
exit(0);
}
if (!is_dir($UPDATE_TMP_DIR)) {
if (!mkdir($UPDATE_TMP_DIR, 0755, true)) {
fail_internal("Impossible de créer le répertoire temporaire: $UPDATE_TMP_DIR");
}
mkdir($UPDATE_TMP_DIR, 0755, true);
}
/**
@@ -51,13 +47,16 @@ function fetch_manifest($url) {
global $UPDATE_TIMEOUT_TOTAL;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $UPDATE_TIMEOUT_TOTAL);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $UPDATE_TIMEOUT_TOTAL,
CURLOPT_FAILONERROR => true,
CURLOPT_FOLLOWLOCATION => true
]);
$content = curl_exec($ch);
if (curl_errno($ch)) {
log_error("manifest_download_failed", "Impossible de télécharger le manifeste", ["url" => $url, "error" => curl_error($ch)]);
log_error("manifest_download_failed", "Échec téléchargement manifeste", ["url" => $url, "err" => curl_error($ch)]);
return false;
}
curl_close($ch);
@@ -66,30 +65,15 @@ function fetch_manifest($url) {
$lines = explode("\n", trim($content));
foreach ($lines as $line) {
$line = trim($line);
if (empty($line)) continue;
// Validation format: hash(64) mode(3) path
if (preg_match('/^([0-9a-fA-F]{64})\s+(644|755)\s+((bin|lib|conf)\/[A-Za-z0-9._\/-]+)$/', $line, $matches)) {
$manifest_entries[] = [
'hash' => $matches[1],
'mode' => $matches[2],
'path' => $matches[3]
];
if (preg_match('/^([0-9a-fA-F]{64})\s+(644|755)\s+((bin|lib|conf)\/[A-Za-z0-9._\/-]+)$/', trim($line), $matches)) {
$manifest_entries[] = ['hash' => $matches[1], 'mode' => $matches[2], 'path' => $matches[3]];
}
}
if (empty($manifest_entries)) {
log_error("manifest_invalid", "Le manifeste distant est invalide ou vide", ["url" => $url]);
return false;
}
log_info("manifest_downloaded", "Manifeste téléchargé", ["url" => $url]);
return $manifest_entries;
}
/**
* Met à jour un fichier spécifique
* Met à jour un fichier
*/
function update_one_file($entry) {
global $MONITORING_BASE_DIR, $UPDATE_BASE_URL, $UPDATE_TMP_DIR, $UPDATE_TIMEOUT_TOTAL;
@@ -99,129 +83,86 @@ function update_one_file($entry) {
$remote_url = rtrim($UPDATE_BASE_URL, '/') . '/' . $rel_path;
$expected_hash = strtolower($entry['hash']);
// Calcul du hash local actuel
$local_hash = file_exists($target_file) ? hash_file('sha256', $target_file) : "";
if ($local_hash === $expected_hash) {
log_debug("update_not_needed", "Fichier déjà à jour", ["file" => $rel_path]);
return true;
if (file_exists($target_file) && hash_file('sha256', $target_file) === $expected_hash) {
return true;
}
// Téléchargement
$tmp_file = $UPDATE_TMP_DIR . '/' . basename($rel_path) . '.' . uniqid();
$ch = curl_init($remote_url);
$fp = fopen($tmp_file, 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_TIMEOUT, $UPDATE_TIMEOUT_TOTAL);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt_array($ch, [
CURLOPT_FILE => $fp,
CURLOPT_TIMEOUT => $UPDATE_TIMEOUT_TOTAL,
CURLOPT_FAILONERROR => true,
CURLOPT_FOLLOWLOCATION => true
]);
$success = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
fclose($fp);
if (!$success) {
log_error("update_download_failed", "Téléchargement impossible", ["file" => $rel_path, "url" => $remote_url, "error" => $error]);
if (!$success || hash_file('sha256', $tmp_file) !== $expected_hash) {
log_error("update_failed", "Fichier invalide ou corrompu", ["file" => $rel_path]);
@unlink($tmp_file);
return false;
}
// Vérification Hash
$downloaded_hash = hash_file('sha256', $tmp_file);
if ($downloaded_hash !== $expected_hash) {
log_error("update_hash_mismatch", "Hash téléchargé invalide", ["file" => $rel_path, "expected" => $expected_hash, "got" => $downloaded_hash]);
@unlink($tmp_file);
return false;
}
// Installation
ensure_parent_dir($target_file);
chmod($tmp_file, octdec($entry['mode']));
if (!rename($tmp_file, $target_file)) {
fail_internal("Échec du déplacement de $tmp_file vers $target_file");
}
if ($local_hash === "") {
log_notice("file_created", "Fichier créé depuis le manifeste", ["file" => $rel_path, "mode" => $entry['mode']]);
} else {
log_notice("update_applied", "Mise à jour appliquée", ["file" => $rel_path, "old_hash" => $local_hash, "new_hash" => $expected_hash]);
}
safe_mv($tmp_file, $target_file); // Utilise la fonction safe_mv de ta lib
log_notice("file_updated", "Mise à jour appliquée", ["file" => $rel_path]);
return true;
}
/**
* Supprime les fichiers locaux absents du manifeste
* Nettoyage
*/
function delete_extra_files($remote_files) {
global $UPDATE_ALLOW_DELETE, $MONITORING_BASE_DIR;
if (!$UPDATE_ALLOW_DELETE) return;
global $UPDATE_ALLOW_DELETE, $MONITORING_BASE_DIR, $SCRIPT_PATH;
if (!$UPDATE_ALLOW_DELETE) return;
$directories = ['bin', 'lib', 'conf'];
foreach ($directories as $dir) {
$full_path = $MONITORING_BASE_DIR . '/' . $dir;
if (!is_dir($full_path)) continue;
foreach (['bin', 'lib', 'conf'] as $dir) {
$full_path = $MONITORING_BASE_DIR . '/' . $dir;
if (!is_dir($full_path)) continue;
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($full_path, RecursiveDirectoryIterator::SKIP_DOTS)
);
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($full_path, RecursiveDirectoryIterator::SKIP_DOTS));
foreach ($iterator as $file) {
// On récupère le chemin relatif par rapport à la racine du monitoring
$rel_path = substr($file->getPathname(), strlen($MONITORING_BASE_DIR) + 1);
// 1. Protection : Si c'est dans le manifeste distant, on ne touche à rien
if (in_array($rel_path, $remote_files)) {
continue;
}
foreach ($iterator as $file) {
$path = $file->getPathname();
$rel_path = substr($path, strlen($MONITORING_BASE_DIR) + 1);
// PROTECTIONS
if (in_array($rel_path, $remote_files)) continue;
if (str_contains($rel_path, '.local.')) continue; // Protection fichiers locaux
if ($path === $SCRIPT_PATH) continue; // Ne pas se suicider
// 2. Protection générique : On n'efface JAMAIS les fichiers de configuration locale
// Cela couvre : *.local.conf.php, *.local.conf, et même *.local.php par sécurité
if (str_ends_with($rel_path, '.local.conf.php') ||
str_ends_with($rel_path, '.local.conf') ||
str_ends_with($rel_path, '.local.php')) {
log_debug("delete_skipped", "Fichier local protégé (ignoré)", ["file" => $rel_path]);
continue;
}
// 3. Suppression si le fichier est obsolète et non protégé
if (@unlink($file->getPathname())) {
log_notice("file_deleted", "Fichier obsolète supprimé", ["file" => $rel_path]);
} else {
log_error("delete_failed", "Impossible de supprimer le fichier local", ["file" => $rel_path]);
}
}
}
if (@unlink($path)) {
log_notice("file_deleted", "Fichier obsolète supprimé", ["file" => $rel_path]);
}
}
}
}
// --- Main ---
$manifest = fetch_manifest($UPDATE_MANIFEST_URL);
if ($manifest === false) exit(2);
if (!$manifest) exit(2);
$total = count($manifest);
$updated = 0;
$failed = 0;
$remote_paths = [];
$updated = 0; $failed = 0;
foreach ($manifest as $entry) {
$remote_paths[] = $entry['path'];
if (update_one_file($entry)) {
$updated++;
} else {
$failed++;
}
update_one_file($entry) ? $updated++ : $failed++;
}
delete_extra_files($remote_paths);
if ($failed > 0) {
log_warning("update_finished_with_errors", "Mise à jour terminée avec erreurs", ["total" => $total, "updated" => $updated, "failed" => $failed]);
log_warning("update_partial", "Mise à jour terminée avec erreurs", ["failed" => $failed]);
} else {
log_info("update_finished", "Mise à jour terminée", ["total" => $total, "updated" => $updated]);
log_info("update_ok", "Mise à jour terminée avec succès");
}
exit_with_status();