diff --git a/install.sh b/install.sh index d023c13..3a91d3c 100755 --- a/install.sh +++ b/install.sh @@ -178,10 +178,10 @@ process_deployment_files "$destination_dir" "$source_dir" "$file_local_desc" ## Declarations ## # Spécifier le chemin du répertoire destination -destination_dir="$HOME/.local/share/doc" +destination_dir="$HOME/.local/share/doc/scripts-bash" # Spécifier le chemin du répertoire du dépôt Git local -source_dir="local/share/doc" +source_dir="local/share/doc/scripts-bash" file_local_desc=.config/files_local-share-doc @@ -198,10 +198,10 @@ process_deployment_files "$destination_dir" "$source_dir" "$file_local_desc" ## Declarations ## # Spécifier le chemin du répertoire -destination_dir="$HOME/.local/share/man" +destination_dir="$HOME/.local/share/man/man1" # Spécifier le chemin du répertoire du dépôt Git local -source_dir="local/share/man" +source_dir="local/share/man/man1" file_local_desc=.config/files_local-share-man @@ -209,12 +209,12 @@ file_local_desc=.config/files_local-share-man log "## Debut du traitement pour $destination_dir" log "### Debut du Traitement pour la gestion du PATH avec $destination_dir" -# Vérifier si le répertoire destination est déjà dans le PATH -if [[ ! ":$(manpath):" == *":$destination_dir:"* ]]; then - # Ajouter le répertoire destination au PATH dans le fichier de configuration de session de l'utilisateur - echo 'export MANPATH="$(manpath):'"$destination_dir"'"' >> ~/.bashrc +# man cherche dans $MANPATH/man1/, on ajoute le parent ~/.local/share/man +manpath_parent="$HOME/.local/share/man" +if [[ ! ":$(manpath):" == *":$manpath_parent:"* ]]; then + echo 'export MANPATH="$(manpath):'"$manpath_parent"'"' >> ~/.bashrc source ~/.bashrc - log " $destination_dir a été ajouté au MANPATH dans le fichier de configuration de session de l'utilisateur." + log " $manpath_parent a été ajouté au MANPATH dans le fichier de configuration de session de l'utilisateur." fi process_deployment_files "$destination_dir" "$source_dir" "$file_local_desc" diff --git a/liste des scripts.base b/liste-des-scripts.base similarity index 100% rename from liste des scripts.base rename to liste-des-scripts.base diff --git a/local/share/doc/castopod_update.1.md b/local/share/doc/scripts-bash/castopod_update.1.md similarity index 100% rename from local/share/doc/castopod_update.1.md rename to local/share/doc/scripts-bash/castopod_update.1.md diff --git a/local/share/doc/convertPDF.1.md b/local/share/doc/scripts-bash/convertPDF.1.md similarity index 100% rename from local/share/doc/convertPDF.1.md rename to local/share/doc/scripts-bash/convertPDF.1.md diff --git a/local/share/doc/play_tophoraire.1.md b/local/share/doc/scripts-bash/play_tophoraire.1.md similarity index 100% rename from local/share/doc/play_tophoraire.1.md rename to local/share/doc/scripts-bash/play_tophoraire.1.md diff --git a/local/share/doc/playlist_gen.1.md b/local/share/doc/scripts-bash/playlist_gen.1.md similarity index 100% rename from local/share/doc/playlist_gen.1.md rename to local/share/doc/scripts-bash/playlist_gen.1.md diff --git a/local/share/doc/random_music_player.1.md b/local/share/doc/scripts-bash/random_music_player.1.md similarity index 100% rename from local/share/doc/random_music_player.1.md rename to local/share/doc/scripts-bash/random_music_player.1.md diff --git a/local/share/man/castopod_update.1 b/local/share/man/man1/castopod_update.1 similarity index 100% rename from local/share/man/castopod_update.1 rename to local/share/man/man1/castopod_update.1 diff --git a/local/share/man/convertPDF.1 b/local/share/man/man1/convertPDF.1 similarity index 100% rename from local/share/man/convertPDF.1 rename to local/share/man/man1/convertPDF.1 diff --git a/local/share/man/play_tophoraire.1 b/local/share/man/man1/play_tophoraire.1 similarity index 100% rename from local/share/man/play_tophoraire.1 rename to local/share/man/man1/play_tophoraire.1 diff --git a/local/share/man/playlist_gen.1 b/local/share/man/man1/playlist_gen.1 similarity index 100% rename from local/share/man/playlist_gen.1 rename to local/share/man/man1/playlist_gen.1 diff --git a/local/share/man/random_music_player.1 b/local/share/man/man1/random_music_player.1 similarity index 100% rename from local/share/man/random_music_player.1 rename to local/share/man/man1/random_music_player.1 diff --git a/prep.sh b/prep.sh index ee6d5c4..b4d61cd 100755 --- a/prep.sh +++ b/prep.sh @@ -58,14 +58,14 @@ ls local/bin/ -1 >.config/files_local-bin # 4. Lister des fichiers dans local/share/ytdll et share/ytdll/lib # Spécifier le chemin du répertoire du dépôt Git local -source_dir="local/share/doc" +source_dir="local/share/doc/scripts-bash" -# Spécifier le chemin du répertoire -destination_dir="local/share/man" +# Spécifier le chemin du répertoire +destination_dir="local/share/man/man1" create_dir "$destination_dir" -log "Lister les fichiers présents dans local/share/doc" +log "Lister les fichiers présents dans local/share/doc/scripts-bash" ls "$source_dir/" -1 >.config/files_local-share-doc log "Creer les pages MAN" @@ -118,8 +118,8 @@ else error " Le fichier $file_local_desc est introuvable." fi -log "Lister les fichiers présents dans local/share/man" -ls local/share/man/ -1 >.config/files_local-share-man +log "Lister les fichiers présents dans local/share/man/man1" +ls local/share/man/man1/ -1 >.config/files_local-share-man log "Lister les fichiers présents dans local/share/ytdll" ls local/share/ytdll/ -1 >.config/files_local-share-ytdll @@ -131,7 +131,7 @@ ls local/share/ytdll/lib/ -1 >.config/files_local-share-ytdll-lib # Résumé des DOC -for fichier in local/share/doc/*.md; do +for fichier in local/share/doc/scripts-bash/*.md; do echo "Résumé pour $fichier :" description_found=0 description_started=0 diff --git a/servers/linux/monitoring/bin/monitoring-update-config.php b/servers/linux/monitoring/bin/monitoring-update-config.php index 1909e7c..4ff8b3a 100755 --- a/servers/linux/monitoring/bin/monitoring-update-config.php +++ b/servers/linux/monitoring/bin/monitoring-update-config.php @@ -1,13 +1,11 @@ #!/usr/bin/env php ou "KEY" => - preg_match_all('/[\'"]([A-Z0-9_]+)[\'"]\s*=>/i', $content, $matches); - $keys = $matches[1] ?? []; - sort($keys); - return array_unique($keys); +function log_clean($level, $msg) { + $color = ['info' => '34', 'notice' => '32', 'warn' => '33', 'err' => '31'][$level] ?? '37'; + echo sprintf("\e[%sm[%s]\e[0m %s\n", $color, strtoupper($level), $msg); } /** - * Logique de logging + * Nettoie un fichier local en comparant ses valeurs avec la base */ -function log_audit($level, $event, $msg) { - echo sprintf("[%s] %s: %s\n", strtoupper($level), $event, $msg); -} +function clean_local_config($base_file, $local_file) { + // On inclut les fichiers pour récupérer les tableaux de config + $base_cfg = include $base_file; + $local_cfg = include $local_file; -function check_config_drift() { - $found_issue = false; - $reviewed_files = 0; - $files_requiring_action = 0; + if (!is_array($base_cfg) || !is_array($local_cfg)) { + return false; + } - log_audit('info', 'audit_start', "Début de l'audit des configurations PHP"); + $new_local_cfg = $local_cfg; + $removed_keys = []; - // On cherche les fichiers .php qui ne sont pas des .local.php - $base_files = glob(CONF_DIR . '/*.php'); - $base_files = array_filter($base_files, function($f) { - return !str_ends_with($f, '.local.php'); - }); - - foreach ($base_files as $base_conf) { - $reviewed_files++; - $base_name = basename($base_conf); - $local_conf = str_replace('.php', '.local.php', $base_conf); - $local_name = basename($local_conf); - - // 1. Si le fichier local n'existe pas - if (!file_exists($local_conf)) { - if (copy($base_conf, $local_conf)) { - chmod($local_conf, 0600); - log_audit('notice', 'audit_missing_local', "Le fichier $local_name a été créé par copie de $base_name"); - } else { - log_audit('error', 'audit_create_local_failed', "Impossible de créer $local_name"); - $found_issue = true; - $files_requiring_action++; - } - continue; - } - - // 2. Comparaison des clés - $keys_base = extract_keys($base_conf); - $keys_local = extract_keys($local_conf); - - $missing = array_diff($keys_base, $keys_local); // Présent dans base mais pas local - $obsolete = array_diff($keys_local, $keys_base); // Présent dans local mais plus dans base - - if (!empty($missing) || !empty($obsolete)) { - $found_issue = true; - $files_requiring_action++; - - log_audit('warning', 'audit_file_requires_action', "Vérification requise pour $local_name"); - - if (!empty($missing)) { - log_audit('warning', 'audit_keys_missing', "Options absentes de $local_name : " . implode(', ', $missing)); - } - - if (!empty($obsolete)) { - log_audit('info', 'audit_keys_obsolete', "Options obsolètes ou personnalisées dans $local_name : " . implode(', ', $obsolete)); - } - } else { - log_audit('info', 'audit_file_ok', "Le fichier $local_name est synchronisé avec $base_name"); + foreach ($local_cfg as $key => $value) { + // Si la clé existe en base ET que la valeur est strictement identique + if (array_key_exists($key, $base_cfg) && $base_cfg[$key] === $value) { + unset($new_local_cfg[$key]); + $removed_keys[] = $key; } } - // Résumé final - if (!$found_issue) { - log_audit('info', 'audit_success', "Toutes les configurations sont à jour ($reviewed_files fichiers vérifiés)"); - } else { - log_audit('warning', 'audit_requires_action', "Action requise sur $files_requiring_action fichier(s) sur $reviewed_files"); + if (empty($removed_keys)) { + log_clean('info', basename($local_file) . " est déjà optimisé."); + return true; } + + // Reconstruction du fichier PHP proprement + $content = " $value) { + $val_export = var_export($value, true); + $content .= " '$key' => $val_export,\n"; + } + $content .= "];\n"; + + if (file_put_contents($local_file, $content)) { + log_clean('notice', basename($local_file) . " nettoyé. Clés supprimées (identiques à la base) : " . implode(', ', $removed_keys)); + return true; + } + + return false; } // --- Main --- -check_config_drift(); \ No newline at end of file + +log_clean('info', "Début de l'optimisation des configurations locales..."); + +$base_files = glob(CONF_DIR . '/*.php'); +foreach ($base_files as $base_conf) { + // On ignore les fichiers .local.php et .conf.local.php + if (str_contains($base_conf, '.local.')) continue; + + // Détermination du nom du fichier local correspondant + // Gère tes deux formats : monitoring.local.conf.php et alert-engine.conf.local.php + $local_conf = str_replace('.conf.php', '.conf.local.php', $base_conf); + if (!file_exists($local_conf)) { + $local_conf = str_replace('.php', '.local.php', $base_conf); + } + + if (file_exists($local_conf)) { + clean_local_config($base_conf, $local_conf); + } +} + +log_clean('info', "Optimisation terminée."); \ No newline at end of file diff --git a/servers/linux/monitoring/old-bin/alert-engine.conf b/servers/linux/monitoring/old-bin/alert-engine.conf deleted file mode 100644 index f4efd3f..0000000 --- a/servers/linux/monitoring/old-bin/alert-engine.conf +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash -# Copyright (C) 2026 Cédric Abonnel -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# Fichiers d'état -ALERT_STATE_FILE="${MONITORING_STATE_DIR}/alert-engine.offset" -ALERT_DEDUP_FILE="${MONITORING_STATE_DIR}/alert-engine.dedup" - -# Activation des canaux -ALERT_NTFY_ENABLED="true" -ALERT_MAIL_ENABLED="true" - -# Mail -ALERT_MAIL_BIN="/usr/sbin/sendmail" -ALERT_MAIL_SUBJECT_PREFIX="[monitoring]" - -# ntfy -NTFY_SERVER="https://ntfy.sh" -NTFY_TOPIC="TPOSOB84sBJ6HTZ7" -NTFY_TOKEN="" - -# Déduplication en secondes -ALERT_DEDUP_WINDOW=3600 - -# Événements à ignorer -ALERT_IGNORE_EVENTS="update_not_needed alert_sent_ntfy alert_sent_mail" - -# Règles par défaut selon le niveau -ALERT_DEFAULT_CHANNELS_WARNING="ntfy" -ALERT_DEFAULT_CHANNELS_ERROR="ntfy,mail" -ALERT_DEFAULT_CHANNELS_CRITICAL="ntfy,mail" - -# Règles spécifiques par événement -ALERT_RULE_disk_usage_high="ntfy" -ALERT_RULE_disk_usage_critical="ntfy,mail" -ALERT_RULE_check_failed="ntfy,mail" -ALERT_RULE_internal_error="ntfy,mail" - -ALERT_RULE_update_hash_unavailable="ntfy" -ALERT_RULE_update_download_failed="ntfy,mail" -ALERT_RULE_update_hash_mismatch="ntfy,mail" -ALERT_RULE_manifest_download_failed="ntfy,mail" -ALERT_RULE_manifest_invalid="ntfy,mail" -ALERT_RULE_update_finished_with_errors="ntfy,mail" - -# Optionnel : certains événements peuvent être forcés en ntfy uniquement -# ALERT_RULE_disk_ok="" -# ALERT_RULE_update_finished="" - -# Optionnel : URL ouverte quand on clique sur la notif ntfy -NTFY_CLICK_URL="" - -# Optionnel : tags par niveau pour ntfy -NTFY_TAGS_WARNING="warning" -NTFY_TAGS_ERROR="warning,rotating_light" -NTFY_TAGS_CRITICAL="skull,warning" \ No newline at end of file diff --git a/servers/linux/monitoring/old-bin/alert-engine.sh b/servers/linux/monitoring/old-bin/alert-engine.sh deleted file mode 100755 index 46a3250..0000000 --- a/servers/linux/monitoring/old-bin/alert-engine.sh +++ /dev/null @@ -1,352 +0,0 @@ -#!/bin/bash -# Copyright (C) 2026 Cédric Abonnel -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -set -u - -SCRIPT_NAME="$(basename "$0")" -SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || echo "$0")" - -# shellcheck source=/opt/monitoring/lib/monitoring-lib.sh -. /opt/monitoring/lib/monitoring-lib.sh || exit 3 - -load_conf_if_exists "/opt/monitoring/conf/alert-engine.conf" -load_conf_if_exists "/opt/monitoring/conf/alert-engine.local.conf" - -lock_or_exit "alert-engine" -require_cmd awk sed grep date tail stat cut tr - -LOG_SOURCE="${LOG_FILE:-/var/log/monitoring/events.jsonl}" -STATE_FILE="${ALERT_STATE_FILE:-/var/lib/monitoring/alert-engine.offset}" -DEDUP_FILE="${ALERT_DEDUP_FILE:-/var/lib/monitoring/alert-engine.dedup}" - -mkdir -p "$(dirname "$STATE_FILE")" "$(dirname "$DEDUP_FILE")" || fail_internal "Impossible de créer les répertoires d'état" -touch "$STATE_FILE" "$DEDUP_FILE" || fail_internal "Impossible d'initialiser les fichiers d'état" - -json_get() { - local key="$1" - local line="$2" - - printf '%s\n' "$line" \ - | sed -n "s/.*\"${key}\":\"\([^\"]*\)\".*/\1/p" \ - | head -n1 -} - -json_get_number() { - local key="$1" - local line="$2" - - printf '%s\n' "$line" \ - | sed -n "s/.*\"${key}\":\([0-9][0-9]*\).*/\1/p" \ - | head -n1 -} - -get_last_offset() { - local offset - offset="$(cat "$STATE_FILE" 2>/dev/null || true)" - if [[ "$offset" =~ ^[0-9]+$ ]]; then - printf '%s\n' "$offset" - else - printf '0\n' - fi -} - -set_last_offset() { - printf '%s\n' "$1" > "$STATE_FILE" -} - -current_log_size() { - stat -c '%s' "$LOG_SOURCE" 2>/dev/null || printf '0\n' -} - -cleanup_dedup_file() { - local now window tmp - now="$(date +%s)" - window="${ALERT_DEDUP_WINDOW:-3600}" - tmp="$(mktemp "${MONITORING_STATE_DIR}/alert-engine.dedup.XXXXXX")" || return 0 - - awk -F'|' -v now="$now" -v window="$window" ' - NF >= 2 { - if ((now - $2) <= window) print $0 - } - ' "$DEDUP_FILE" > "$tmp" 2>/dev/null || true - - mv -f "$tmp" "$DEDUP_FILE" 2>/dev/null || true -} - -dedup_key() { - local host="$1" - local app="$2" - local level="$3" - local event="$4" - printf '%s|%s|%s|%s\n' "$host" "$app" "$level" "$event" -} - -should_notify_dedup() { - local key="$1" - local now window found_ts - now="$(date +%s)" - window="${ALERT_DEDUP_WINDOW:-3600}" - - found_ts="$(awk -F'|' -v k="$key" ' - $1 "|" $3 "|" $4 "|" $5 == k {print $2} - ' "$DEDUP_FILE" | tail -n1)" - - if [[ "$found_ts" =~ ^[0-9]+$ ]]; then - if [ $((now - found_ts)) -lt "$window" ]; then - return 1 - fi - fi - - return 0 -} - - -save_dedup_entry() { - local host="$1" - local app="$2" - local level="$3" - local event="$4" - local now - now="$(date +%s)" - printf '%s|%s|%s|%s|%s\n' "$host" "$now" "$app" "$level" "$event" >> "$DEDUP_FILE" -} - -event_is_ignored() { - local event="$1" ignored - for ignored in ${ALERT_IGNORE_EVENTS:-}; do - [ "$ignored" = "$event" ] && return 0 - done - return 1 -} - -channels_for_event() { - local level="$1" - local event="$2" - local varname value - - varname="ALERT_RULE_${event}" - value="${!varname:-}" - - if [ -n "$value" ]; then - printf '%s\n' "$value" - return 0 - fi - - case "$level" in - WARNING) - printf '%s\n' "${ALERT_DEFAULT_CHANNELS_WARNING:-ntfy}" - ;; - ERROR) - printf '%s\n' "${ALERT_DEFAULT_CHANNELS_ERROR:-ntfy,mail}" - ;; - CRITICAL) - printf '%s\n' "${ALERT_DEFAULT_CHANNELS_CRITICAL:-ntfy,mail}" - ;; - *) - printf '\n' - ;; - esac -} - -tags_for_level() { - case "$1" in - WARNING) printf '%s\n' "${NTFY_TAGS_WARNING:-warning}" ;; - ERROR) printf '%s\n' "${NTFY_TAGS_ERROR:-warning,rotating_light}" ;; - CRITICAL) printf '%s\n' "${NTFY_TAGS_CRITICAL:-skull,warning}" ;; - *) printf '\n' ;; - esac -} - - -send_ntfy() { - - local title="$1" - local body="$2" - local priority="$3" - - [ "${ALERT_NTFY_ENABLED:-true}" = "true" ] || return 0 - [ -n "${NTFY_SERVER:-}" ] || return 1 - [ -n "${NTFY_TOPIC:-}" ] || return 1 - - local url="${NTFY_SERVER%/}/${NTFY_TOPIC}" - - local curl_args=( - -fsS - -X POST - -H "Title: ${title}" - -H "Priority: ${priority}" - -H "Tags: warning" - -d "$body" - ) - - # topic protégé - if [ -n "${NTFY_TOKEN:-}" ]; then - curl_args+=(-H "Authorization: Bearer ${NTFY_TOKEN}") - fi - - curl "${curl_args[@]}" "$url" >/dev/null -} - -send_mail() { - local subject="$1" - local body="$2" - - [ "${ALERT_MAIL_ENABLED:-true}" = "true" ] || return 0 - [ -n "${DEST:-}" ] || return 1 - [ -x "${ALERT_MAIL_BIN:-/usr/sbin/sendmail}" ] || return 1 - - { - printf 'To: %s\n' "${DEST}" - printf 'Subject: %s %s\n' "${ALERT_MAIL_SUBJECT_PREFIX:-[monitoring]}" "$subject" - printf 'Content-Type: text/plain; charset=UTF-8\n' - printf '\n' - printf '%s\n' "$body" - } | "${ALERT_MAIL_BIN:-/usr/sbin/sendmail}" -t -} - -priority_for_level() { - case "$1" in - CRITICAL) printf 'urgent\n' ;; - ERROR) printf 'high\n' ;; - WARNING) printf 'default\n' ;; - *) printf 'default\n' ;; - esac -} - -build_title() { - local host="$1" - local app="$2" - local level="$3" - local event="$4" - printf '%s [%s] %s %s\n' "$host" "$app" "$level" "$event" -} - -build_body() { - local ts="$1" - local host="$2" - local app="$3" - local level="$4" - local event="$5" - local message="$6" - local line="$7" - - cat </dev/null || realpath "$0" 2>/dev/null || echo "$0")}" - -STATUS_OK=0 -STATUS_WARNING=1 -STATUS_ERROR=2 -STATUS_INTERNAL=3 - -CURRENT_STATUS=$STATUS_OK - -LOG_LEVEL=${LOG_LEVEL:-INFO} - -json_escape() { - local s="${1:-}" - s="${s//\\/\\\\}" - s="${s//\"/\\\"}" - s="${s//$'\n'/\\n}" - s="${s//$'\r'/\\r}" - s="${s//$'\t'/\\t}" - printf '%s' "$s" -} - -log_event() { - local level="$1" - local event="$2" - local message="$3" - shift 3 - - local ts extra key value kv host - ts="$(date --iso-8601=seconds)" - - # Détection dynamique du hostname si HOSTNAME_FQDN n'est pas défini - # On utilise 'hostname -f' pour le nom complet ou 'hostname' en secours - host="${HOSTNAME_FQDN:-$(hostname -f 2>/dev/null || hostname)}" - - extra="" - - for kv in "$@"; do - key="${kv%%=*}" - value="${kv#*=}" - extra="${extra},\"$(json_escape "$key")\":\"$(json_escape "$value")\"" - done - - # Utilisation de la variable 'host' détectée ci-dessus - printf '{"ts":"%s","host":"%s","app":"%s","level":"%s","event":"%s","message":"%s"%s}\n' \ - "$(json_escape "$ts")" \ - "$(json_escape "$host")" \ - "$(json_escape "$SCRIPT_NAME")" \ - "$(json_escape "$level")" \ - "$(json_escape "$event")" \ - "$(json_escape "$message")" \ - "$extra" >> "${LOG_FILE:-/var/log/monitoring/events.jsonl}" -} - -set_status() { - local new_status="$1" - if [ "$new_status" -gt "$CURRENT_STATUS" ]; then - CURRENT_STATUS="$new_status" - fi -} - -log_debug() { log_event "DEBUG" "$@"; } -log_info() { log_event "INFO" "$@"; } -log_notice() { log_event "NOTICE" "$@"; } -log_warning() { log_event "WARNING" "$@"; set_status "$STATUS_WARNING"; } -log_error() { log_event "ERROR" "$@"; set_status "$STATUS_ERROR"; } -log_critical() { log_event "CRITICAL" "$@"; set_status "$STATUS_ERROR"; } - -fail_internal() { - log_event "ERROR" "internal_error" "$1" - exit "$STATUS_INTERNAL" -} - -exit_with_status() { - exit "$CURRENT_STATUS" -} - -require_cmd() { - local cmd - for cmd in "$@"; do - command -v "$cmd" >/dev/null 2>&1 || fail_internal "Commande requise absente: $cmd" - done -} - -load_conf_if_exists() { - local conf="$1" - [ -f "$conf" ] && . "$conf" -} - -lock_or_exit() { - local lock_name="${1:-$SCRIPT_NAME}" - local lock_file="${MONITORING_LOCK_DIR:-/var/lock/monitoring}/${lock_name}.lock" - - exec 9>"$lock_file" || fail_internal "Impossible d'ouvrir le lock $lock_file" - flock -n 9 || { - log_notice "already_running" "Une autre instance est déjà en cours" "lock=$lock_file" - exit 0 - } -} - -threshold_level() { - local value="$1" - local warning="$2" - local critical="$3" - - if [ "$value" -ge "$critical" ]; then - printf 'CRITICAL' - elif [ "$value" -ge "$warning" ]; then - printf 'WARNING' - else - printf 'INFO' - fi -} - -safe_mv() { - local src="$1" - local dst="$2" - mv -f "$src" "$dst" || fail_internal "Échec du déplacement de $src vers $dst" -} - -ensure_parent_dir() { - local file="$1" - mkdir -p "$(dirname "$file")" || fail_internal "Impossible de créer le répertoire parent de $file" -} \ No newline at end of file diff --git a/servers/linux/monitoring/old-bin/monitoring-update-config.sh b/servers/linux/monitoring/old-bin/monitoring-update-config.sh deleted file mode 100755 index ac0c602..0000000 --- a/servers/linux/monitoring/old-bin/monitoring-update-config.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/bash -# Copyright (C) 2026 Cédric Abonnel -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -set -u - -SCRIPT_NAME="$(basename "$0")" -. /opt/monitoring/lib/monitoring-lib.sh || exit 3 - -# On s'assure d'avoir les permissions root -if [ "${EUID}" -ne 0 ]; then - echo "Ce script doit être exécuté en root." >&2 - exit 1 -fi - -extract_keys() { - local file="$1" - grep -E '^[A-Za-z_][A-Za-z0-9_]*=' "$file" | cut -d'=' -f1 | sort -u -} - -check_config_drift() { - local conf_dir="/opt/monitoring/conf" - local base_conf local_conf - local found_issue=false - local reviewed_files=0 - local files_requiring_action=0 - - log_info "audit_start" "Début de l'audit des configurations locales" - - while IFS= read -r base_conf; do - reviewed_files=$((reviewed_files + 1)) - - local_conf="${base_conf%.conf}.local.conf" - local file_name local_file_name - file_name="$(basename "$base_conf")" - local_file_name="$(basename "$local_conf")" - - if [ ! -f "$local_conf" ]; then - cp "$base_conf" "$local_conf" || { - log_error "audit_create_local_failed" \ - "Impossible de créer ${local_file_name} à partir de ${file_name}" - found_issue=true - files_requiring_action=$((files_requiring_action + 1)) - continue - } - chmod 600 "$local_conf" 2>/dev/null || true - - log_notice "audit_missing_local" \ - "Le fichier ${local_file_name} n'existait pas ; il a été créé par copie de ${file_name}" - continue - fi - - local tmp_base tmp_local - tmp_base="$(mktemp)" || fail_internal "mktemp a échoué" - tmp_local="$(mktemp)" || fail_internal "mktemp a échoué" - - extract_keys "$base_conf" > "$tmp_base" - extract_keys "$local_conf" > "$tmp_local" - - local missing obsolete - missing="$(comm -23 "$tmp_base" "$tmp_local" | xargs)" - obsolete="$(comm -13 "$tmp_base" "$tmp_local" | xargs)" - - if [ -n "$missing" ] || [ -n "$obsolete" ]; then - found_issue=true - files_requiring_action=$((files_requiring_action + 1)) - - log_warning "audit_file_requires_action" \ - "Le fichier ${local_file_name} nécessite une vérification" - - if [ -n "$missing" ]; then - log_warning "audit_keys_missing" \ - "Dans ${local_file_name}, options disponibles dans ${file_name} mais absentes du local : ${missing}" - fi - - if [ -n "$obsolete" ]; then - log_info "audit_keys_obsolete" \ - "Dans ${local_file_name}, options présentes uniquement dans le local et à vérifier ou supprimer : ${obsolete}" - fi - else - log_info "audit_file_ok" \ - "Le fichier ${local_file_name} contient les mêmes options que ${file_name}" - fi - - rm -f "$tmp_base" "$tmp_local" - done < <(find "$conf_dir" -maxdepth 1 -type f -name "*.conf" ! -name "*.local.conf" | sort) - - if [ "$found_issue" = false ]; then - log_info "audit_success" \ - "Toutes les configurations locales sont à jour (${reviewed_files} fichier(s) vérifié(s))" - else - log_warning "audit_requires_action" \ - "Certaines configurations locales doivent être mises à jour (${files_requiring_action} fichier(s) à vérifier sur ${reviewed_files})" - fi -} - -main() { - lock_or_exit "monitoring-audit" - check_config_drift -} - -main -exit_with_status \ No newline at end of file diff --git a/servers/linux/monitoring/old-bin/monitoring-update.sh b/servers/linux/monitoring/old-bin/monitoring-update.sh deleted file mode 100755 index 57a97f8..0000000 --- a/servers/linux/monitoring/old-bin/monitoring-update.sh +++ /dev/null @@ -1,247 +0,0 @@ -#!/bin/bash -# Copyright (C) 2026 Cédric Abonnel -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# Moteur de mise à jour des programmes et fichiers connexes - -set -u - -SCRIPT_NAME="$(basename "$0")" -SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || echo "$0")" - -# shellcheck source=/opt/monitoring/lib/monitoring-lib.sh -. /opt/monitoring/lib/monitoring-lib.sh || exit 3 - -load_conf_if_exists "/opt/monitoring/conf/autoupdate.conf" -load_conf_if_exists "/opt/monitoring/conf/autoupdate.local.conf" - -# Définir les variables par défaut si elles ne sont pas dans les fichiers .conf -UPDATE_TMP_DIR="${UPDATE_TMP_DIR:-/tmp/monitoring-update}" -UPDATE_TIMEOUT_CONNECT="${UPDATE_TIMEOUT_CONNECT:-3}" -UPDATE_TIMEOUT_TOTAL="${UPDATE_TIMEOUT_TOTAL:-15}" -UPDATE_MANIFEST_URL="${UPDATE_MANIFEST_URL:-}" -UPDATE_BASE_URL="${UPDATE_BASE_URL:-}" - -lock_or_exit "monitoring-update" -require_cmd curl sha256sum awk mktemp chmod dirname mv rm grep sed sort comm cut tr find - -[ "${UPDATE_ENABLED:-true}" = "true" ] || { - log_notice "update_disabled" "Mise à jour désactivée par configuration" - exit 0 -} - -mkdir -p "${UPDATE_TMP_DIR:-/tmp/monitoring-update}" || fail_internal "Impossible de créer le répertoire temporaire" - -TMP_MANIFEST="$(mktemp "${UPDATE_TMP_DIR}/manifest.XXXXXX")" || fail_internal "mktemp a échoué" -TMP_LOCAL_LIST="$(mktemp "${UPDATE_TMP_DIR}/local.XXXXXX")" || fail_internal "mktemp a échoué" -TMP_REMOTE_LIST="$(mktemp "${UPDATE_TMP_DIR}/remote.XXXXXX")" || fail_internal "mktemp a échoué" - -cleanup() { - rm -f "$TMP_MANIFEST" "$TMP_LOCAL_LIST" "$TMP_REMOTE_LIST" -} -trap cleanup EXIT - -fetch_manifest() { - if ! curl -fsS \ - --connect-timeout "${UPDATE_TIMEOUT_CONNECT:-3}" \ - --max-time "${UPDATE_TIMEOUT_TOTAL:-15}" \ - "${UPDATE_MANIFEST_URL}" \ - -o "$TMP_MANIFEST"; then - log_error "manifest_download_failed" \ - "Impossible de télécharger le manifeste" \ - "url=${UPDATE_MANIFEST_URL}" - return 1 - fi - - if ! awk ' - NF == 3 && - $1 ~ /^[0-9a-fA-F]{64}$/ && - $2 ~ /^(644|755)$/ && - $3 ~ /^(bin|lib|conf)\/[A-Za-z0-9._\/-]+$/ && - $3 !~ /\.\./ - ' "$TMP_MANIFEST" >/dev/null; then - log_error "manifest_invalid" \ - "Le manifeste distant est invalide" \ - "url=${UPDATE_MANIFEST_URL}" - return 1 - fi - - log_info "manifest_downloaded" "Manifeste téléchargé" "url=${UPDATE_MANIFEST_URL}" - return 0 -} - -list_remote_files() { - awk '{print $3}' "$TMP_MANIFEST" | sort -u > "$TMP_REMOTE_LIST" -} - -list_local_files() { - find "${MONITORING_BASE_DIR}/bin" "${MONITORING_BASE_DIR}/lib" "${MONITORING_BASE_DIR}/conf" \ - -type f 2>/dev/null \ - | sed "s#^${MONITORING_BASE_DIR}/##" \ - | sort -u > "$TMP_LOCAL_LIST" -} - -apply_mode() { - local mode="$1" - local file="$2" - - case "$mode" in - 755) chmod 755 "$file" ;; - 644) chmod 644 "$file" ;; - *) fail_internal "Mode non supporté: $mode" ;; - esac -} - -update_one_file() { - local expected_hash="$1" - local mode="$2" - local rel_path="$3" - - local local_file="${MONITORING_BASE_DIR}/${rel_path}" - local remote_file="${UPDATE_BASE_URL}/${rel_path}" - local tmp_file local_hash downloaded_hash - - tmp_file="$(mktemp "${UPDATE_TMP_DIR}/$(basename "$rel_path").XXXXXX")" || fail_internal "mktemp a échoué" - - if [ -f "$local_file" ]; then - local_hash="$(sha256sum "$local_file" | awk '{print $1}')" - else - local_hash="" - fi - - if [ "$local_hash" = "$expected_hash" ]; then - log_debug "update_not_needed" "Fichier déjà à jour" "file=$rel_path" - rm -f "$tmp_file" - return 0 - fi - - if ! curl -fsS \ - --connect-timeout "${UPDATE_TIMEOUT_CONNECT:-3}" \ - --max-time "${UPDATE_TIMEOUT_TOTAL:-15}" \ - "$remote_file" \ - -o "$tmp_file"; then - log_error "update_download_failed" \ - "Téléchargement impossible" \ - "file=$rel_path" "url=$remote_file" - rm -f "$tmp_file" - return 1 - fi - - downloaded_hash="$(sha256sum "$tmp_file" | awk '{print $1}')" - if [ "$downloaded_hash" != "$expected_hash" ]; then - log_error "update_hash_mismatch" \ - "Hash téléchargé invalide" \ - "file=$rel_path" "expected=$expected_hash" "got=$downloaded_hash" - rm -f "$tmp_file" - return 1 - fi - - ensure_parent_dir "$local_file" - apply_mode "$mode" "$tmp_file" - safe_mv "$tmp_file" "$local_file" - - if [ -z "$local_hash" ]; then - log_notice "file_created" \ - "Fichier créé depuis le manifeste" \ - "file=$rel_path" "mode=$mode" "hash=$expected_hash" - else - log_notice "update_applied" \ - "Mise à jour appliquée" \ - "file=$rel_path" "mode=$mode" "old_hash=$local_hash" "new_hash=$expected_hash" - fi - - return 0 -} - -delete_extra_local_files() { - [ "${UPDATE_ALLOW_DELETE:-false}" = "true" ] || return 0 - - comm -23 "$TMP_LOCAL_LIST" "$TMP_REMOTE_LIST" | while IFS= read -r rel_path; do - [ -n "$rel_path" ] || continue - - # Protection globale de TOUS les fichiers .local.conf - if [[ "$rel_path" == *.local.conf ]]; then - log_notice "delete_skipped" \ - "Fichier local protégé (ignoré)" \ - "file=$rel_path" - continue - fi - - # Sécurité supplémentaire pour ne pas supprimer les répertoires vitaux - rm -f "${MONITORING_BASE_DIR}/${rel_path}" \ - && log_notice "file_deleted" \ - "Fichier obsolète supprimé" \ - "file=$rel_path" \ - || log_error "delete_failed" \ - "Échec suppression" \ - "file=$rel_path" - done -} - -run_local_conf_sync() { - - local sync_script="${MONITORING_BASE_DIR}/bin/sync-local-confs.sh" - - if [ -x "$sync_script" ]; then - log_info "local_conf_sync_start" \ - "Synchronisation des fichiers .local.conf" - - if "$sync_script"; then - log_info "local_conf_sync_done" \ - "Synchronisation terminée" - else - log_warning "local_conf_sync_failed" \ - "La synchronisation des .local.conf a échoué" - fi - else - log_notice "local_conf_sync_missing" \ - "Script de synchronisation absent" \ - "script=$sync_script" - fi -} - -main() { - local total=0 updated_or_checked=0 failed=0 - local hash mode path - - fetch_manifest || exit 2 - list_remote_files - list_local_files - - while read -r hash mode path; do - [ -n "${hash:-}" ] || continue - total=$((total + 1)) - - if update_one_file "$hash" "$mode" "$path"; then - updated_or_checked=$((updated_or_checked + 1)) - else - failed=$((failed + 1)) - fi - done < "$TMP_MANIFEST" - - delete_extra_local_files - - run_local_conf_sync - - if [ "$failed" -gt 0 ]; then - log_warning "update_finished_with_errors" \ - "Mise à jour terminée avec erreurs" \ - "total=$total" "updated_or_checked=$updated_or_checked" "failed=$failed" - else - log_info "update_finished" \ - "Mise à jour terminée" \ - "total=$total" "updated_or_checked=$updated_or_checked" "failed=0" - fi -} - -main -exit_with_status \ No newline at end of file diff --git a/servers/linux/monitoring/old-bin/monitoring.conf b/servers/linux/monitoring/old-bin/monitoring.conf deleted file mode 100644 index 580f7fe..0000000 --- a/servers/linux/monitoring/old-bin/monitoring.conf +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# Configuration globale par défaut - NE PAS ÉDITER (Utilisez .local.conf) - -MONITORING_BASE="/opt/monitoring" -MONITORING_LOG_DIR="/var/log/monitoring" -MONITORING_STATE_DIR="/var/lib/monitoring" -MONITORING_LOCK_DIR="/var/lock/monitoring" - -LOG_FILE="${MONITORING_LOG_DIR}/events.jsonl" - -HOSTNAME_FQDN="$(hostname -f 2>/dev/null || hostname)" - -DEST="root" - -NTFY_SERVER="nfy.sh" -NTFY_TOPIC="TPOSOB84sBJ6HTZ7" -NTFY_TOKEN="" - -UPDATE_ENABLED="true" -UPDATE_BASE_URL="https://git.abonnel.fr/cedricAbonnel/scripts-bash/raw/branch/main/servers/linux/monitoring" -UPDATE_MANIFEST_URL="${UPDATE_BASE_URL}/manifest.txt" -UPDATE_TIMEOUT_CONNECT=3 -UPDATE_TIMEOUT_TOTAL=15 -UPDATE_TMP_DIR="/tmp/monitoring-update" -UPDATE_ALLOW_DELETE="false" - -mkdir -p "$MONITORING_LOG_DIR" "$MONITORING_STATE_DIR" "$MONITORING_LOCK_DIR" 2>/dev/null || true \ No newline at end of file diff --git a/servers/linux/monitoring/old-bin/monitoring.sh b/servers/linux/monitoring/old-bin/monitoring.sh deleted file mode 100755 index 93a33e3..0000000 --- a/servers/linux/monitoring/old-bin/monitoring.sh +++ /dev/null @@ -1,208 +0,0 @@ -#!/bin/bash -# Copyright (C) 2026 Cédric Abonnel -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# lit le fichier log - -set -u - -SCRIPT_NAME="$(basename "$0")" -SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || echo "$0")" - -# shellcheck source=/opt/monitoring/lib/monitoring-lib.sh -. /opt/monitoring/lib/monitoring-lib.sh || exit 3 - -load_conf_if_exists "/opt/monitoring/conf/autoupdate.conf" - -lock_or_exit "monitoring-update" -require_cmd curl sha256sum awk mktemp chmod dirname mv rm grep sed sort comm cut tr - -[ "${UPDATE_ENABLED:-true}" = "true" ] || { - log_notice "update_disabled" "Mise à jour désactivée par configuration" - exit 0 -} - -mkdir -p "${UPDATE_TMP_DIR:-/tmp/monitoring-update}" || fail_internal "Impossible de créer le répertoire temporaire" - -TMP_MANIFEST="$(mktemp "${UPDATE_TMP_DIR}/manifest.XXXXXX")" || fail_internal "mktemp a échoué" -TMP_LOCAL_LIST="$(mktemp "${UPDATE_TMP_DIR}/local.XXXXXX")" || fail_internal "mktemp a échoué" -TMP_REMOTE_LIST="$(mktemp "${UPDATE_TMP_DIR}/remote.XXXXXX")" || fail_internal "mktemp a échoué" - -cleanup() { - rm -f "$TMP_MANIFEST" "$TMP_LOCAL_LIST" "$TMP_REMOTE_LIST" -} -trap cleanup EXIT - -fetch_manifest() { - if ! curl -fsS \ - --connect-timeout "${UPDATE_TIMEOUT_CONNECT:-3}" \ - --max-time "${UPDATE_TIMEOUT_TOTAL:-15}" \ - "${UPDATE_MANIFEST_URL}" \ - -o "$TMP_MANIFEST"; then - log_error "manifest_download_failed" "Impossible de télécharger le manifeste" "url=${UPDATE_MANIFEST_URL}" - return 1 - fi - - if ! awk ' - NF == 3 && - $1 ~ /^[0-9a-fA-F]{64}$/ && - $2 ~ /^(644|755)$/ && - $3 ~ /^(bin|lib|conf)\/[A-Za-z0-9._\/-]+$/ && - $3 !~ /\.\./ - ' "$TMP_MANIFEST" >/dev/null; then - log_error "manifest_invalid" "Le manifeste distant est invalide" "url=${UPDATE_MANIFEST_URL}" - return 1 - fi - - log_info "manifest_downloaded" "Manifeste téléchargé" "url=${UPDATE_MANIFEST_URL}" - return 0 -} - -list_remote_files() { - awk '{print $3}' "$TMP_MANIFEST" | sort -u > "$TMP_REMOTE_LIST" -} - -list_local_files() { - find "${MONITORING_BASE_DIR}/bin" "${MONITORING_BASE_DIR}/lib" "${MONITORING_BASE_DIR}/conf" \ - -type f 2>/dev/null \ - | sed "s#^${MONITORING_BASE_DIR}/##" \ - | sort -u > "$TMP_LOCAL_LIST" -} - -apply_mode() { - local mode="$1" - local file="$2" - - case "$mode" in - 755) chmod 755 "$file" ;; - 644) chmod 644 "$file" ;; - *) fail_internal "Mode non supporté: $mode" ;; - esac -} - -update_one_file() { - local expected_hash="$1" - local mode="$2" - local rel_path="$3" - - local local_file="${MONITORING_BASE_DIR}/${rel_path}" - local remote_file="${UPDATE_BASE_URL}/${rel_path}" - local tmp_file local_hash downloaded_hash - - tmp_file="$(mktemp "${UPDATE_TMP_DIR}/$(basename "$rel_path").XXXXXX")" || fail_internal "mktemp a échoué" - - if [ -f "$local_file" ]; then - local_hash="$(sha256sum "$local_file" | awk '{print $1}')" - else - local_hash="" - fi - - if [ "$local_hash" = "$expected_hash" ]; then - log_debug "update_not_needed" "Fichier déjà à jour" "file=$rel_path" - rm -f "$tmp_file" - return 0 - fi - - if ! curl -fsS \ - --connect-timeout "${UPDATE_TIMEOUT_CONNECT:-3}" \ - --max-time "${UPDATE_TIMEOUT_TOTAL:-15}" \ - "$remote_file" \ - -o "$tmp_file"; then - log_error "update_download_failed" "Téléchargement impossible" "file=$rel_path" "url=$remote_file" - rm -f "$tmp_file" - return 1 - fi - - downloaded_hash="$(sha256sum "$tmp_file" | awk '{print $1}')" - if [ "$downloaded_hash" != "$expected_hash" ]; then - log_error "update_hash_mismatch" "Hash téléchargé invalide" \ - "file=$rel_path" "expected=$expected_hash" "got=$downloaded_hash" - rm -f "$tmp_file" - return 1 - fi - - ensure_parent_dir "$local_file" - apply_mode "$mode" "$tmp_file" - safe_mv "$tmp_file" "$local_file" - - if [ -z "$local_hash" ]; then - log_notice "file_created" "Fichier créé depuis le manifeste" \ - "file=$rel_path" "mode=$mode" "hash=$expected_hash" - else - log_notice "update_applied" "Mise à jour appliquée" \ - "file=$rel_path" "mode=$mode" "old_hash=$local_hash" "new_hash=$expected_hash" - fi - - return 0 -} - -delete_extra_local_files() { - - [ "${UPDATE_ALLOW_DELETE:-false}" = "true" ] || return 0 - - comm -23 "$TMP_LOCAL_LIST" "$TMP_REMOTE_LIST" | while IFS= read -r rel_path; do - - [ -n "$rel_path" ] || continue - - case "$rel_path" in - conf/autoupdate.conf|conf/alert-engine.local.conf) - log_notice "delete_skipped" \ - "Suppression ignorée pour fichier local protégé" \ - "file=$rel_path" - continue - ;; - esac - - rm -f "${MONITORING_BASE_DIR}/${rel_path}" \ - && log_notice "file_deleted" \ - "Fichier supprimé car absent du manifeste" \ - "file=$rel_path" \ - || log_error "delete_failed" \ - "Impossible de supprimer fichier local" \ - "file=$rel_path" - - done -} - -main() { - local total=0 updated=0 failed=0 hash mode path - - fetch_manifest || exit 2 - list_remote_files - list_local_files - - while read -r hash mode path; do - [ -n "${hash:-}" ] || continue - total=$((total + 1)) - - if update_one_file "$hash" "$mode" "$path"; then - updated=$((updated + 1)) - else - failed=$((failed + 1)) - fi - done < "$TMP_MANIFEST" - - delete_extra_local_files - - if [ "$failed" -gt 0 ]; then - log_warning "update_finished_with_errors" \ - "Mise à jour terminée avec erreurs" \ - "total=$total" "updated_or_checked=$updated" "failed=$failed" - else - log_info "update_finished" \ - "Mise à jour terminée" \ - "total=$total" "updated_or_checked=$updated" "failed=0" - fi -} - -main -exit_with_status \ No newline at end of file