# Gere par Set-OPS (role serveur_prometheus). Ne pas editer a la main. global: scrape_interval: {{ serveur_prometheus_intervalle }} scrape_configs: - job_name: prometheus static_configs: - targets: ['localhost:9090'] - job_name: node {% if serveur_prometheus_metriques_tls | default(false) %} scheme: https tls_config: ca_file: {{ serveur_prometheus_metriques_ca }} {% endif %} static_configs: {# `intersect` rend un ENSEMBLE : son ordre d'iteration n'est pas stable d'un processus Python a l'autre. Sans `sort`, ce fichier se rendait differemment a chaque passage — memes quatorze cibles, ordre different — et Prometheus etait redemarre pour rien. Trouve par le passage d'idempotence du 2026-08-09. On trie sur les HOTES : ordre deterministe et lisible par un humain. #} - targets: {{ (groups.get(serveur_prometheus_groupe_metriques, []) | intersect(groups.get('hotes_actifs', [])) | sort) | map('extract', hostvars) | selectattr('ansible_host', 'defined') | map(attribute='ansible_host') | map('regex_replace', '$', ':' ~ serveur_prometheus_port_node) | list | to_json }} {# --- LES CIBLES QUE LES ROLES DECLARENT (2026-09-14) --------------------------- Chaque `roles//meta/metriques.yml` decrit son exportateur ; le nom du DOSSIER est le nom du GROUPE, donc les cibles sont les hotes actifs de ce groupe. UN ROLE DECLARE SANS HOTE NE PRODUIT AUCUN JOB. Prometheus n'a pas a porter une cible qui n'existe pas, et son journal n'a pas a se remplir de refus previsibles. ORDRE STABLE : `sort` sur les hotes, comme pour `node` juste au-dessus. Sans lui, le fichier se rend differemment a chaque passage et Prometheus redemarre pour rien — defaut trouve le 2026-08-09, qu'on ne va pas reintroduire ici. #} {% for decl in serveur_prometheus_declarations.results | default([]) %} {% set role = decl.item.path | dirname | dirname | basename %} {% set meta = decl.content | b64decode | from_yaml %} {% set expo = meta.exportateur | default(none) %} {% set cibles = (groups.get(role, []) | intersect(groups.get('hotes_actifs', [])) | sort) | map('extract', hostvars) | selectattr('ansible_host', 'defined') | map(attribute='ansible_host') | map('regex_replace', '$', ':' ~ (expo.port | default(0))) | list %} {% if expo and cibles %} - job_name: {{ expo.job }} static_configs: - targets: {{ cibles | to_json }} {% endif %} {% endfor %} {# Les cibles ECRITES AU PLAN completent la derivation, elles ne la remplacent pas : un equipement ou un service tiers n'a aucun role Set-OPS pour le declarer. #} {% for job in serveur_prometheus_cibles_supplementaires %} - job_name: {{ job.job }} static_configs: {% if job.hotes | default({}) %} {# UNE CIBLE NOMMEE PAR BLOC : l'etiquette `hote` s'attache a un `static_config`, pas a une adresse. Les series disent alors « asgard », pas « 192.168.11.41:9100 ». #} {% for cible in job.cibles %} - targets: {{ [cible] | to_json }} labels: hote: {{ job.hotes[cible] | default(cible) | to_json }} {% endfor %} {% else %} - targets: {{ job.cibles | to_json }} {% endif %} {% endfor %}