Compare commits

..
23 Commits
Author SHA1 Message Date
hcornet c46836ab1c Dix-neuf packs applicatifs : JMX, API REST, SNMP
build / Garde-fou (push) Successful in 11m43s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m57s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m29s
2026-09-12 11:31:25 +02:00
hcornet 9debdcdf9c Chaque pack apporte son propre calendrier de notification
build / Garde-fou (push) Successful in 10m45s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m52s
build / Images Harbor (web, Dockerfile) (push) Successful in 10m0s
2026-09-12 11:02:02 +02:00
hcornet 032982cb28 Le calendrier livre par Centreon figure au projet sans etre recree
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m52s
build / Garde-fou (push) Successful in 10m45s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m18s
2026-09-12 10:04:11 +02:00
hcornet bc18f93196 Import d'un pack par la route de fusion, champs fermes, correction des champs vides
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m44s
build / Garde-fou (push) Successful in 10m44s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m25s
2026-09-11 21:15:23 +02:00
hcornet ec195cac8f Masquer les packs deja importes dans la fenetre d'import
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m52s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m15s
build / Garde-fou (push) Successful in 10m41s
2026-09-11 19:32:39 +02:00
hcornet 2187a1971e Groupes d'hotes : objet HG et suggestions dans le champ de l'hote
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m49s
build / Garde-fou (push) Successful in 10m37s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m15s
2026-09-11 19:06:36 +02:00
hcornet 23395779ee Catalogue range selon les categories des connecteurs Centreon
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m47s
build / Garde-fou (push) Successful in 10m40s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m13s
2026-09-11 17:56:54 +02:00
hcornet d2f11c3879 Treize packs materiel : baies de disques, commutateurs, wifi
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m47s
build / Garde-fou (push) Successful in 10m37s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m14s
2026-09-11 17:04:02 +02:00
hcornet 3879b63a88 Corps du message compose de blocs, macros Centreon en suggestion
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m50s
build / Garde-fou (push) Successful in 10m27s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m25s
2026-09-11 16:46:31 +02:00
hcornet cdfa377f46 Perimetres de notification et rattachement des modeles
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m58s
build / Garde-fou (push) Successful in 10m22s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m11s
2026-09-11 15:59:40 +02:00
hcornet ac929c6878 Interface honnete sur l'acces aux comptes, fenetre de contribution
build / Garde-fou (push) Successful in 10m21s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m48s
build / Images Harbor (web, Dockerfile) (push) Successful in 9m57s
2026-09-11 14:05:32 +02:00
hcornet 714470031d Message explicite quand le pack ou la branche existe deja
build / Garde-fou (push) Successful in 10m22s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Canceled after 0s
build / Images Harbor (web, Dockerfile) (push) Canceled after 0s
2026-09-11 13:54:18 +02:00
hcornet 8559aca4d7 Agent utilisateur pour Gitea, messages d'erreur exploitables
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m45s
build / Garde-fou (push) Successful in 10m22s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m6s
2026-09-11 12:50:27 +02:00
hcornet c411f2933d Corrige la bascule du catalogue, detecte un changement de depot, compte les packs a l'import
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m45s
build / Garde-fou (push) Successful in 10m18s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m10s
2026-09-11 12:16:57 +02:00
hcornet 469305b4a7 Page d'accueil, mentions legales, licence, guide de contribution, catalogue porte a 39 packs
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m43s
build / Garde-fou (push) Successful in 9m36s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m31s
2026-09-11 10:50:43 +02:00
hcornet 6c602c97ad Alembic construit le moteur directement, sans passer par le fichier ini
build / Garde-fou (pull_request) Successful in 9m29s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (pull_request) Skipped
build / Images Harbor (web, Dockerfile) (pull_request) Skipped
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m44s
build / Garde-fou (push) Successful in 9m31s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m8s
2026-09-11 08:54:56 +02:00
hcornet 5659c32b66 Honore les entetes du proxy, URI de retour testee, contraste du bouton de connexion
build / Garde-fou (pull_request) Successful in 9m29s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (pull_request) Skipped
build / Images Harbor (web, Dockerfile) (pull_request) Skipped
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m40s
build / Garde-fou (push) Successful in 9m29s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m6s
2026-09-10 21:30:47 +02:00
hcornet 5766e24213 Alembic et le point d'entree lisent la configuration de l'application
build / Garde-fou (pull_request) Successful in 9m19s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (pull_request) Skipped
build / Images Harbor (web, Dockerfile) (pull_request) Skipped
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m45s
build / Garde-fou (push) Successful in 9m19s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m10s
2026-09-10 20:58:40 +02:00
hcornet acf72da7f8 Revue statique, conventions documentees, construction arm64 limitee aux versions et cache de couches
build / Garde-fou (pull_request) Successful in 9m21s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (pull_request) Skipped
build / Images Harbor (web, Dockerfile) (pull_request) Skipped
build / Garde-fou (push) Successful in 9m20s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m44s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m7s
2026-09-10 18:28:29 +02:00
hcornet 6d02ec0c18 Assemble l'URL de base a partir d'elements separes, mot de passe encode
build / Garde-fou (pull_request) Successful in 18s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m42s
build / Garde-fou (push) Successful in 18s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m7s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (pull_request) Skipped
build / Images Harbor (web, Dockerfile) (pull_request) Skipped
2026-09-10 17:40:34 +02:00
hcornet 90609bd3d2 Declare requests, importe par Authlib sans etre declare
build / Garde-fou (pull_request) Successful in 18s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m42s
build / Garde-fou (push) Successful in 18s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m2s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (pull_request) Skipped
build / Images Harbor (web, Dockerfile) (pull_request) Skipped
2026-09-10 16:44:46 +02:00
hcornet b063d59525 Partage par lien, comptes Authentik, soumission et moderation de packs, prerequis des sondes ; corrige le lien casse vers le script de l'editeur
build / Garde-fou (pull_request) Failing after 7s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (pull_request) Skipped
build / Images Harbor (web, Dockerfile) (pull_request) Skipped
build / Garde-fou (push) Failing after 8s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Skipped
build / Images Harbor (web, Dockerfile) (push) Skipped
2026-09-10 16:28:26 +02:00
hcornet 3f0046c208 Etiquettes Traefik alignees sur l'installation, tmpfs gunicorn, dependances bornees
build / Garde-fou (pull_request) Successful in 10s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (pull_request) Skipped
build / Images Harbor (web, Dockerfile) (pull_request) Skipped
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m45s
build / Garde-fou (push) Successful in 11s
build / Images Harbor (web, Dockerfile) (push) Successful in 11m26s
2026-09-10 15:27:26 +02:00
123 changed files with 10512 additions and 423 deletions

No files matched your search

+31 -2
View File
@@ -5,7 +5,7 @@ ENCLUME_REGISTRY=registry.tips-of-mine.com
ENCLUME_TAG=1.0.0
# Publication
ENCLUME_DOMAINE=clapi.tips-of-mine.com
ENCLUME_DOMAINE=enclume.tips-of-mine.com
TRAEFIK_RESOLVER=cloudflare
TZ=Europe/Paris
GUNICORN_WORKERS=2
@@ -17,5 +17,34 @@ CATALOG_SUBDIR=catalog
SYNC_INTERVAL=300
CATALOG_SUBDIR=catalog
# Base de donnees (chantier 2)
# Base de donnees. Le mot de passe peut contenir n'importe quel caractere :
# l'application assemble l'URL de connexion et l'encode elle-meme.
POSTGRES_PASSWORD=a-remplacer
# Sessions : generer avec openssl rand -hex 32
ENCLUME_SECRET_KEY=a-remplacer
ENCLUME_PARTAGE_JOURS=90
# Connexion optionnelle par Authentik (laisser vide pour un site sans comptes)
ENCLUME_OIDC_METADATA=https://authentik.tips-of-mine.com/application/o/enclume/.well-known/openid-configuration
ENCLUME_OIDC_CLIENT_ID=
ENCLUME_OIDC_CLIENT_SECRET=
# Laisser a 0 tant que le fournisseur d'identite n'accepte pas les inscriptions :
# le site propose alors de contribuer par demande de fusion plutot qu'une
# connexion impossible a obtenir.
ENCLUME_INSCRIPTION_OUVERTE=0
ENCLUME_ADMIN_GROUPE=enclume-admins
# Depannage du premier demarrage, avant le mapping de portee "groups" :
ENCLUME_ADMIN_COMPTES=
# Mentions legales, affichees sur /mentions
ENCLUME_EDITEUR=Prenom Nom, particulier
ENCLUME_CONTACT=[email protected]
ENCLUME_HEBERGEUR=Auto-heberge, France
ENCLUME_DEPOT=https://gitea.tips-of-mine.com/Tips-Of-Mine/Enclume
# Publication des packs acceptes, sous forme de demandes de fusion
ENCLUME_GITEA_URL=https://gitea.tips-of-mine.com
ENCLUME_GITEA_TOKEN=
ENCLUME_GITEA_PROPRIETAIRE=Tips-Of-Mine
ENCLUME_GITEA_DEPOT=Enclume
+32 -2
View File
@@ -27,11 +27,24 @@ jobs:
# evalue mal cette expression dans un bloc "with". La variable
# ci-dessus reste la reference lue par les humains.
python-version: "3.12"
- run: pip install -r requirements.txt pytest
cache: pip
- run: pip install -r requirements.txt pytest ruff
- name: Revue statique
run: python -m ruff check .
- run: python -m pytest -q
- name: Coherence du catalogue
run: python -m enclume.cli --list > /dev/null
# L'editeur est verifie dans un vrai DOM : deux defauts d'interface ont
# deja echappe aux tests Python, sans jamais produire d'erreur serveur.
- name: Interface
run: sh tests/interface.sh
# La synchronisation du catalogue, sur un depot Git local : le defaut du
# 11/09 annoncait des publications reussies sans jamais basculer le lien.
- name: Synchronisation du catalogue
run: sh tests/sync.sh
images:
name: Images Harbor
runs-on: ubuntu-latest
@@ -48,7 +61,9 @@ jobs:
steps:
- uses: actions/checkout@v4
# QEMU n'est necessaire que pour l'arm64, donc uniquement sur les tags.
- name: Preparer QEMU
if: gitea.ref_type == 'tag'
uses: docker/setup-qemu-action@v3
- name: Preparer Buildx
@@ -72,13 +87,24 @@ jobs:
type=sha,format=long
type=ref,event=branch
- name: Choisir les architectures
id: arch
run: |
# L'arm64 passe par l'emulation QEMU et coute plusieurs dizaines de
# minutes. On ne le paie qu'au moment de publier une version.
if [ "${{ gitea.ref_type }}" = "tag" ]; then
echo "plateformes=linux/amd64,linux/arm64" >> "$GITHUB_OUTPUT"
else
echo "plateformes=linux/amd64" >> "$GITHUB_OUTPUT"
fi
- name: Construire et pousser
id: push
uses: docker/build-push-action@v6
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64,linux/arm64
platforms: ${{ steps.arch.outputs.plateformes }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
@@ -90,6 +116,10 @@ jobs:
# unknown/unknown que Harbor affiche mal et que son scanner ignore.
provenance: false
sbom: false
# Sans cache, chaque construction reinstalle toutes les dependances.
# Le cache vit dans Harbor, a cote des images.
cache-from: type=registry,ref=${{ vars.HARBOR_HOST }}/${{ vars.HARBOR_PROJECT }}/${{ matrix.composant }}:cache
cache-to: type=registry,ref=${{ vars.HARBOR_HOST }}/${{ vars.HARBOR_PROJECT }}/${{ matrix.composant }}:cache,mode=max
- name: Declencher le scan Harbor
env:
+1 -9
View File
@@ -1,9 +1 @@
.venv/
__pycache__/
*.pyc
.pytest_cache/
.env
.env.*
!.env.example
sortie/
*.zip
node_modules/
+304
View File
@@ -0,0 +1,304 @@
# Journal des versions
Format : [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/).
Versionnement sémantique, comme décrit dans [docs/CONVENTIONS.md](docs/CONVENTIONS.md).
## 1.20.0
### Ajouté
- Dix-neuf packs applicatifs : Tomcat, JVM, Kafka, ActiveMQ et ZooKeeper en JMX ; Graylog,
Wazuh, HashiCorp Vault, Jenkins, Grafana, Prometheus, Veeam Enterprise Manager, Microsoft
IIS et Podman en API REST ; HAProxy, Keepalived, Squid et Microsoft DHCP en SNMP ; PHP-FPM
par sa page de statut
- Catalogue porté à 71 packs et 266 sondes, dont 22 en Applications
## 1.19.0
### Ajouté
- Un périmètre créé à la main reprend le dernier calendrier du projet, et propose d'en créer
un — en permanence ou en heures ouvrées — quand il n'y en a aucun
- Un périmètre sans calendrier est signalé dans son écran ; faute de choix, il vise `24x7`
sur le central, et la validation le rappelle
## 1.18.0
### Modifié
- Chaque pack apporte désormais **son propre** calendrier — `TP-App-Apache-24x7`,
`TP-App-Nginx-24x7`, `TP-HW-Printer-RFC3805-Heures-Ouvrees` — au lieu de pointer celui du
central : ajuster les plages d'une technologie ne modifie plus celles de tout le parc
## 1.17.0
### Modifié
- Le calendrier d'un pack figure désormais dans le projet même quand Centreon le livre :
il portait jusqu'ici une absence qui se lisait comme un oubli. Marqué « Centreon », il
montre ses plages, n'est pas recréé, et un bouton permet de forcer sa création si le
central l'a perdu
## 1.16.0
### Corrigé
- **L'import d'un pack n'apportait toujours que les commandes et les modèles.** La correction
annoncée en 1.11.1 n'avait jamais été appliquée : le remplacement dans l'éditeur avait
échoué en silence, et les tests ne couvraient que la route serveur. L'import passe
désormais par `/api/packs/<id>/fusionner`, et deux tests empruntent le chemin réel
- Les champs sans valeur affichaient le mot « undefined », notamment toutes les plages
horaires d'un calendrier neuf
- Un nouvel hôte rejoignait tous les groupes à chaque affichage : le groupe du dernier pack
importé est désormais pré-coché à la création seulement, et se décoche
### Modifié
- Version SNMP, criticité, calendrier d'un périmètre et commande de vérification deviennent
des listes fermées, avec une option « Autre valeur » qui révèle une saisie quand un objet
propre au central est nécessaire
- La couleur du bandeau se choisit dans un sélecteur de couleur
- Les groupes d'hôtes du projet se cochent ; un champ distinct reçoit ceux qui existent déjà
sur le central
- Un calendrier propose trois modèles de plages : en permanence, heures ouvrées, astreinte
## 1.15.0
### Modifié
- Les packs déjà présents dans le projet sont masqués de la fenêtre d'import, avec un
compteur et un lien pour les afficher : les reproposer n'avait aucun effet, l'import
les ignorait
## 1.14.1
### Modifié
- Le nom affiché dans l'interface devient « Forge Centreon », avec pour baseline
« Générateur de configuration pour Centreon avec CLAPI ». Le projet, le dépôt, les images
et le paquet Python restent « Enclume ».
## 1.14.0
### Ajouté
- Page d'aide « Installer SNMP » : configuration de départ sécurisée pour Debian, Ubuntu,
RHEL, Windows et les équipements réseau, avec la vérification depuis le collecteur
- Valeurs standards proposées pour les modèles parents, la version SNMP, le répertoire des
plugins, le collecteur et la criticité
### Modifié
- Moins de saisie libre : chaque champ qui a des valeurs connues les propose désormais
## 1.13.0
### Ajouté
- Chaque pack livre son groupe d'hôtes : importer un pack donne désormais les commandes,
les modèles, le groupe, le calendrier, le périmètre de notification et les prérequis
- La commande de vérification, ses arguments et le fuseau horaire sur l'hôte, où ils ont
leur place — ils n'existaient que sur le modèle d'hôte
- Un hôte créé après l'import d'un pack rejoint automatiquement son groupe
### Modifié
- Le fuseau horaire se choisit dans une liste fermée, alimentée par la base du système :
une faute de frappe ne se voyait qu'à l'exécution sur le central
- La commande de vérification propose celles livrées par Centreon et celles du projet
## 1.12.0
### Ajouté
- Groupes d'hôtes : objet `HG` créé par le projet, et suggestions dans le champ de l'hôte
- Un hôte peut appartenir à plusieurs groupes ; ceux qui ne sont pas dans le projet sont
signalés sans bloquer, ils peuvent exister sur le central
## 1.11.1
### Corrigé
- L'import d'un pack apportait seulement les commandes et les modèles : le calendrier, le
périmètre de notification, les hôtes et les prérequis étaient perdus en chemin. La fusion
est désormais faite par le serveur, qui connaît tous les objets d'un projet.
## 1.11.0
### Modifié
- Le catalogue adopte les catégories des connecteurs de supervision Centreon —
`operating-system`, `network`, `storage`, `database`, `virtualization`, `protocol`,
`ups-pdu`, `printer` et les autres — au lieu des trois familles maison. Les packs sont
reclassés et les répertoires renommés en conséquence.
## 1.10.0
### Ajouté
- Treize packs matériel : commutateurs Aruba, Extreme, Huawei, Alcatel OmniSwitch et Dell
PowerConnect ; wifi Cisco WLC, Aruba Instant et Ruckus ZoneDirector ; baies Dell EMC Unity,
Pure Storage, HPE MSA, IBM Storwize et NAS QNAP
- Catalogue porté à 52 packs et 224 sondes
## 1.9.0
### Ajouté
- Les 39 packs du catalogue livrent leur chaîne de notification : calendrier selon la
criticité, groupe de contacts dédié, impact métier, et rattachement des modèles d'hôte
et de service au périmètre
- Section `notification` dans le format de pack
### Corrigé
- Les calendriers livrés par Centreon (`24x7`, `workhours`…) sont référencés et non recréés :
`TP;ADD` aurait échoué sur un objet existant et interrompu le déploiement
## 1.8.0
### Ajouté
- Corps du message composé de blocs ordonnables : macro, lien, texte fixe, sortie du contrôle,
définis séparément pour l'hôte et pour le service
- Une quarantaine de macros Centreon proposées en suggestion, dont `$NOTIFICATIONAUTHOR$`,
`$NOTIFICATIONCOMMENT$`, les URL de notes et d'action, les données de performance
- Les macros personnalisées `$_HOSTXXX$` et `$_SERVICEXXX$` sont acceptées
### Modifié
- Une macro sans valeur à l'exécution n'affiche plus de ligne vide
## 1.7.0
### Ajouté
- Aperçu du message de notification dans l'éditeur, pour l'hôte et pour le service
- Gabarit HTML unique, partagé par l'aperçu et le script PHP généré
## 1.6.0
### Ajouté
- Périmètres de notification : calendrier, destinataires, états déclencheurs et contexte
métier — application, responsable, criticité, impact, procédure de reprise
- Calendriers de notification, objets `TP` avec leurs plages horaires
- Génération d'un script PHP par périmètre, avec le shebang `#!/usr/bin/php -c /etc/php.ini`,
et d'un script d'installation qui vérifie la syntaxe avant de déposer
- Paramétrage des contacts et création des groupes de contacts
- Rattachement d'un modèle d'hôte ou de service à un périmètre : calendrier, états
déclencheurs, intervalle et groupe de contacts posés directement sur le modèle
## 1.5.0
### Ajouté
- `ENCLUME_INSCRIPTION_OUVERTE` : tant que le fournisseur d'identité n'accepte pas les
inscriptions, le site propose « Contribuer » plutôt qu'une connexion impossible à obtenir
- Fenêtre expliquant comment proposer ou vérifier un pack sans compte
## 1.4.2
### Corrigé
- Un pack dont le fichier existe déjà dans le dépôt donne un message explicite, au lieu
d'un échec sans motif
- Même chose pour une branche de publication déjà présente
## 1.4.1
### Corrigé
- Agent utilisateur explicite pour les appels à Gitea : `Python-urllib` était rejeté par les
protections placées devant lui
- L'interface affiche le motif renvoyé par le serveur, et à défaut le code HTTP, au lieu
d'un « échec de la requête » sans information
- Message dédié quand une protection bloque la requête avant Gitea
## 1.4.0
### Ajouté
- Notifications en fond plein, vert, orange ou rouge selon la nature du message,
refermables et empilées, en remplacement des fenêtres bloquantes du navigateur
### Modifié
- Le témoin d'enregistrement automatique reste discret dans la barre : il se déclenche
à chaque frappe et n'a pas à interrompre la lecture
## 1.3.2
### Corrigé
- Les ressources statiques portent la version : un visiteur conservait l'ancien script
après une mise à jour, et voyait une interface qui ne correspondait plus au serveur
- Messages de soumission explicites : ce qui manque est nommé, plutôt que la clé Python
## 1.3.1
### Corrigé
- Bascule du catalogue : `mv` vers un lien pointant sur un répertoire le suivait au lieu
de le remplacer, et le site restait figé sur une ancienne révision pendant que la
synchronisation annonçait des publications réussies
- Un changement de dépôt du catalogue provoque désormais un nouveau clone
### Ajouté
- Nombre de packs affiché dans le titre de la fenêtre d'import
- Test de la synchronisation sur un dépôt Git local, exécuté par la CI
## 1.3.0
### Ajouté
- Page d'accueil publique, distincte de l'éditeur désormais servi sur `/editeur`
- Mentions légales et politique de confidentialité sur `/mentions`
- Licence MIT, guide de contribution, journal des versions
- Catalogue porté de 26 à 39 packs et de 124 à 177 sondes : pfSense, Stormshield, Palo Alto,
MikroTik, Ubiquiti, HP ProCurve, onduleurs RFC 1628, Proxmox VE, Redis, MongoDB,
Elasticsearch, RabbitMQ, LDAP
## 1.2.0
### Ajouté
- Route `/health`, convention du web pour un point de santé ; `/sante` reste servi
- Fenêtre de soumission documentée : règles attendues et modèle de pack commenté
### Modifié
- Lien de modération et barre d'outils plus lisibles
## 1.1.8
### Ajouté
- `/health` publie l'URI de redirection OIDC, pour la comparer à celle déclarée
- Normalisation de `ENCLUME_URL_PUBLIQUE` : barre finale, protocole absent
## 1.1.7
### Corrigé
- Alembic construit son moteur directement : un mot de passe encodé contient des `%`,
que le fichier ini prenait pour des interpolations
## 1.1.6
### Corrigé
- Les en-têtes transmis par le proxy sont honorés, sans quoi l'URI de redirection OIDC
était construite en `http://localhost`
## 1.1.5
### Corrigé
- Rendu des modèles de service : une propriété en lecture seule interrompait l'affichage
### Ajouté
- Test d'interface dans un DOM headless, exécuté par la CI
## 1.1.4
### Corrigé
- Alembic et le point d'entrée lisent la configuration de l'application, plus l'environnement
## 1.1.3
### Modifié
- Construction arm64 réservée aux versions, cache de couches dans Harbor
- Analyse statique `ruff` dans la CI
## 1.1.2
### Corrigé
- URL de base assemblée à partir d'éléments séparés : un mot de passe contenant `@`
disloquait l'URL de connexion
## 1.1.1
### Corrigé
- `requests` déclaré explicitement, Authlib l'importe sans le déclarer
## 1.1.0
### Ajouté
- Partage par lien, projets enregistrés, connexion optionnelle via OIDC
- Soumission de packs et modération, publication en demande de fusion Gitea
- Prérequis d'installation des sondes, générés dans un fichier distinct du CLAPI
### Corrigé
- Lien cassé vers le script de l'éditeur, qui rendait l'interface muette
## 1.0.0
### Ajouté
- Éditeur libre : commandes, modèles de service, modèles d'hôte, hôtes
- Catalogue de packs, génération CLAPI, scripts de déploiement et de retour arrière
- Empaquetage Docker, CI Gitea, synchronisation du catalogue depuis Git
+123
View File
@@ -0,0 +1,123 @@
# Contribuer à Enclume
Deux formes de contribution, très différentes par leur difficulté.
## Proposer un pack — le plus utile
Un pack décrit une technologie : un modèle d'hôte et ses sondes. C'est ce qui fait la valeur
d'Enclume, et c'est accessible à quiconque supervise cette technologie au quotidien.
**Depuis le site**, bouton « Proposer un pack » : collez votre YAML, il est vérifié
immédiatement, et une demande de fusion est ouverte après relecture.
**Par pull request**, si vous préférez : un fichier dans `catalog/<catégorie>/<id>.yml`.
### Le format
```yaml
id: app-rabbitmq # minuscules, chiffres et tirets
name: RabbitMQ # nom lisible, affiché dans le catalogue
category: applications # une des catégories ci-dessous
status: to-verify # verified seulement si éprouvé sur un central réel
plugin: centreon_rabbitmq_restapi.pl
description: Supervision d'un broker RabbitMQ via son API de management.
host_template:
name: App-RabbitMQ-custom # <Famille>-<Techno>-custom
alias: Applicatif RabbitMQ
parents: [generic-active-host-custom]
macros:
- {name: RABBITPORT, value: "15672", description: "Port de l'API"}
- {name: RABBITPASSWORD, value: "", description: "Mot de passe", is_password: true}
prerequis: # facultatif mais précieux
paquets:
debian: [libwww-perl]
rhel: [perl-libwww-perl]
notes: |
Activer le plugin de management et créer un compte en lecture seule.
groupe_hote: # le groupe dans lequel ranger les hôtes
name: HG-App-RabbitMQ
alias: RabbitMQ
notification: # la chaîne d'alerte livrée avec le pack
perimetre: RabbitMQ
calendrier: # le pack apporte le sien, il ne réutilise pas celui du central
name: TP-App-RabbitMQ-24x7
modele: 24x7 # 24x7 ou Heures-Ouvrees : le rythme copié
alias: RabbitMQ, en permanence
groupe: CG-App-RabbitMQ # CG-<Famille>-<Techno>
criticite: Majeure
impact: "Échanges entre applications interrompus"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Queues # donnera le modèle App-RabbitMQ-Queues
alias: Queues
description: Messages en attente dans les files
default: true # false pour une sonde décochée par défaut
line: "$CENTREONPLUGINS$/centreon_rabbitmq_restapi.pl --plugin=… --mode=queues …"
macros:
- {name: WARNING, value: "1000", description: "Seuil warning"}
```
### Les catégories
Ce sont celles des connecteurs de supervision Centreon, pour qu'un pack se range là où on
ira le chercher dans la documentation officielle :
`operating-system`, `network`, `hardware-server`, `storage`, `database`, `applications`,
`virtualization`, `protocol`, `ups-pdu`, `printer`, `sensor`, `cloud`, `toip-voip`,
`blockchain`, `centreon`.
Le fichier se dépose dans `catalog/<catégorie>/<id>.yml`, et le champ `category` porte la
même valeur.
### Les règles
- **Pas de point-virgule** dans une ligne de commande : c'est le séparateur CLAPI, il casserait
le fichier d'import.
- **Les seuils en macros** `$_SERVICEXXX$`, jamais en dur. C'est tout l'intérêt d'un modèle.
- **Ce qui est commun à l'hôte va sur l'hôte** : ports, comptes, options du plugin. Ce qui est
propre à une sonde va sur la sonde : seuils, filtres.
- **Aucun mot de passe réel.** Valeur vide et `is_password: true`.
- **Un groupe d'hôtes.** Nommé `HG-<Famille>-<Techno>`. Un hôte sans groupe devient
introuvable dès que le parc grandit, et les droits comme les filtres s'appuient dessus.
- **Une chaîne de notification.** Un pack qui supervise sans prévenir personne n'a pas
d'intérêt : `calendrier`, `groupe` et `impact` sont attendus. Choisissez `24x7` pour ce
dont la panne réveille quelqu'un, `Heures-Ouvrees` sinon. Les calendriers livrés par
Centreon. Chaque pack apporte **son propre** calendrier, nommé `TP-<Famille>-<Techno>-<rythme>` :
ajuster les plages d'une technologie ne doit pas modifier celles de tout le central.
- **`status: verified`** uniquement si vous avez exécuté ces commandes sur un Centreon. Sinon
`to-verify`, c'est honnête et c'est utile.
- `$CENTREONPLUGINS$` est remplacé par le répertoire de plugins choisi par l'utilisateur.
### Le plus précieux
Vérifier un pack existant marqué `to-verify` vaut autant qu'en écrire un nouveau. Un
`--list-mode` sur le plugin concerné, une exécution réelle, et le passage en `verified` :
c'est ce qui rend le catalogue fiable.
## Contribuer au code
```bash
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt pytest ruff
python -m pytest -q
sh tests/interface.sh
```
Avant toute proposition, la revue décrite dans [docs/CONVENTIONS.md](docs/CONVENTIONS.md) :
`ruff check`, la suite de tests, le test d'interface. Les conventions de nommage y sont aussi.
Une règle traverse tout le projet : **le serveur n'exécute jamais rien**. Ni CLAPI, ni
prérequis, ni contribution. Il écrit des fichiers que l'utilisateur relit avant de les jouer.
Toute proposition qui s'en écarte sera refusée, quel que soit son intérêt.
## Signaler un problème
Un pack dont le CLAPI généré ne passe pas sur votre central est un signalement de première
importance : indiquez la version de Centreon, le pack, et le message d'erreur de `centreon`.
+11 -4
View File
@@ -6,9 +6,12 @@ FROM python:3.12-slim AS build
ENV PIP_NO_CACHE_DIR=1 PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /build
# requirements.txt seul dans cette couche : tant qu'il ne change pas, la
# reinstallation des dependances est reprise du cache, meme si le code a bouge.
COPY requirements.txt ./
RUN python -m venv /opt/venv \
&& /opt/venv/bin/pip install --no-cache-dir -r requirements.txt
RUN --mount=type=cache,target=/root/.cache/pip \
python -m venv /opt/venv \
&& /opt/venv/bin/pip install -r requirements.txt
# ------------------------------------------------------------------- execution
FROM python:3.12-slim AS runtime
@@ -40,11 +43,15 @@ COPY --from=build /opt/venv /opt/venv
WORKDIR /app
COPY --chown=root:root enclume/ /app/enclume/
COPY --chown=root:root catalog/ /app/catalog/
COPY --chown=root:root migrations/ /app/migrations/
COPY --chown=root:root alembic.ini /app/alembic.ini
COPY --chown=root:root docker/entrypoint-web.sh /usr/local/bin/entrypoint-web
RUN chmod +x /usr/local/bin/entrypoint-web
USER enclume
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8080/sante', timeout=4).status==200 else 1)"
CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8080/health', timeout=4).status==200 else 1)"
CMD ["sh", "-c", "exec gunicorn --bind 0.0.0.0:8080 --workers ${GUNICORN_WORKERS} --timeout ${GUNICORN_TIMEOUT} --access-logfile - --error-logfile - --forwarded-allow-ips '*' 'enclume.webapp:create_app()'"]
CMD ["/usr/local/bin/entrypoint-web"]
+21 -235
View File
@@ -1,235 +1,21 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based on the Program.
To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
Template-Docker
Copyright (C) 2024 Tips-Of-Mine
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.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements.
You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <http://www.gnu.org/licenses/>.
MIT License
Copyright (c) 2026 Hubert Cornet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+38 -9
View File
@@ -10,7 +10,7 @@ Projet indépendant, sans lien avec Centreon SAS.
- **Éditeur libre** : commandes, modèles de service, modèles d'hôte, hôtes. Héritage,
duplication, rattachement des services aux modèles d'hôte.
- **Catalogue de départ** : 26 packs, environ 124 sondes, importables puis modifiables.
- **Catalogue de départ** : 71 packs, 266 sondes, importables puis modifiables.
- **Validation** avant génération : noms en double, références manquantes, point-virgule
interdit, services rattachés à aucun modèle d'hôte, mots de passe en clair.
- **Quatre fichiers** : `deploy.sh` (avec `--dry-run`), `deploy.clapi` (import CLAPI),
@@ -18,12 +18,23 @@ Projet indépendant, sans lien avec Centreon SAS.
- **Version de Centreon** au niveau du projet : les macros sortent en 3 ou 5 champs selon
la cible.
- **Prérequis d'installation** : un pack peut déclarer ses paquets et ses droits, générés
dans un `prerequis.sh` distinct du CLAPI.
- **Notifications par périmètre** : calendriers, destinataires, états déclencheurs et
message personnalisé par domaine applicatif ou système — voir
[docs/NOTIFICATIONS.md](docs/NOTIFICATIONS.md).
- **Partage par lien**, projets enregistrés et **soumission de packs** quand l'instance est
configurée pour — voir [docs/COMPTES-ET-MODERATION.md](docs/COMPTES-ET-MODERATION.md).
## Ce que le serveur ne fait pas
Le projet vit dans le navigateur du visiteur (`localStorage`), s'exporte en JSON et se
réimporte. Le serveur valide et génère, sans rien conserver. Les macros marquées « mot de
passe » ne sont jamais stockées ni partagées : elles sont vidées avant toute écriture côté
serveur.
Il n'exécute rien. Ni CLAPI, ni prérequis, ni contribution : il écrit des fichiers que
l'utilisateur relit avant de les jouer.
Sans configuration, le projet vit dans le navigateur (`localStorage`), s'exporte en JSON et
se réimporte ; le serveur valide et génère sans rien conserver. Avec une base, le partage et
l'enregistrement deviennent possibles — et les macros marquées « mot de passe » sont vidées
avant toute écriture, quelle qu'elle soit.
## Architecture
@@ -66,10 +77,22 @@ python3 -m enclume.cli --projet mon-projet.json --out ./sortie
|---|---|
| `GET /api/packs` | catalogue |
| `GET /api/packs/<id>/projet` | un pack converti en objets de projet |
| `POST /api/packs/<id>/fusionner` | ajoute un pack au projet en cours |
| `GET /api/fuseaux` | fuseaux horaires connus du système |
| `GET /api/valeurs-standards` | modèles parents, versions SNMP, criticités |
| `GET /aide/snmp` | installer et sécuriser SNMP, par système |
| `GET /api/commandes-usuelles` | commandes de vérification livrées par Centreon |
| `POST /api/valider` | validation seule |
| `POST /api/generer` | validation et génération des quatre fichiers |
| `POST /telecharger` | archive zip |
| `GET /sante` | version, commit, état du catalogue |
| `POST /api/partages` `GET /api/partages/<id>` | partage par lien |
| `GET POST DELETE /api/projets` | projets enregistrés (connexion requise) |
| `POST /api/soumissions/verifier` `POST /api/soumissions` | contribution d'un pack |
| `/api/moderation/...` | file de modération (groupe d'administration) |
| `GET /health` (alias `/sante`) | version, commit, état du catalogue, fonctions actives |
| `GET /` | page d'accueil publique |
| `GET /editeur` | l'éditeur |
| `GET /mentions` | mentions légales et données personnelles |
| `POST /recharger` | relecture du catalogue (appelé par `catalog-sync`) |
## Ajouter un pack au catalogue
@@ -78,6 +101,12 @@ Un pack est un fichier YAML déposé dans `catalog/<catégorie>/`. Le format et
commenté sont dans `catalog/exemple-pack.yml.example`. Aucun code à modifier, aucune image à
reconstruire : `catalog-sync` le prend en charge au prochain cycle.
## Contribuer et livrer
Les conventions de nommage et la revue à passer avant chaque version sont dans
[docs/CONVENTIONS.md](docs/CONVENTIONS.md). En résumé : `ruff check`, la suite de tests, et
une installation en environnement vierge — dans cet ordre, avant tout tag.
## Structure
```
@@ -101,7 +130,7 @@ compose.dev.yaml développement local
1. Éditeur libre — **fait**
2. Empaquetage Docker, CI, exploitation — **fait**
3. Partage par lien et projets enregistrés (PostgreSQL)
4. Connexion optionnelle via Authentik
5. Soumission de packs et modération, écriture dans Gitea
3. Partage par lien et projets enregistrés — **fait**
4. Connexion optionnelle via Authentik — **fait**
5. Soumission de packs et modération, demandes de fusion Gitea — **fait**
6. Habillage public : page d'accueil, mentions, documentation d'usage
+38
View File
@@ -0,0 +1,38 @@
# Migrations de la base Enclume.
# L'URL n'est pas ecrite ici : elle vient de ENCLUME_DATABASE_URL, lue par env.py.
[alembic]
script_location = migrations
prepend_sys_path = .
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
+62
View File
@@ -0,0 +1,62 @@
id: app-activemq-jmx
name: Apache ActiveMQ (JMX)
category: applications
status: to-verify
plugin: centreon_activemq_jmx.pl
description: Supervision d'un courtier ActiveMQ via JMX et l'agent Jolokia.
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
notes: |
Deployer l'agent Jolokia dans la JVM supervisee et exposer son point
d'acces au collecteur : les plugins JMX de Centreon passent par lui.
host_template:
name: App-ActiveMQ-JMX-custom
alias: Applicatif ActiveMQ JMX
parents: [generic-active-host-custom]
macros:
- {name: JMXURL, value: "http://localhost:8080/jolokia", description: "URL de l'agent Jolokia"}
- {name: JMXUSERNAME, value: "", description: "Compte Jolokia"}
- {name: JMXPASSWORD, value: "", description: "Mot de passe Jolokia", is_password: true}
- {name: JMXEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-ActiveMQ-JMX
alias: Apache ActiveMQ (JMX)
notification:
perimetre: Apache ActiveMQ (JMX)
calendrier:
name: TP-App-ActiveMQ-JMX-24x7
modele: 24x7
alias: Apache ActiveMQ (JMX), en permanence
groupe: CG-App-ActiveMQ-JMX
criticite: Majeure
impact: "Files de messages bloquees"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Queues
alias: Queues
description: Messages en attente dans les files
line: "$CENTREONPLUGINS$/centreon_activemq_jmx.pl --plugin=apps::activemq::jmx::plugin --mode=queues --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Topics
alias: Topics
description: Sujets et abonnes
line: "$CENTREONPLUGINS$/centreon_activemq_jmx.pl --plugin=apps::activemq::jmx::plugin --mode=topics --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Broker-Usage
alias: Broker-Usage
description: Memoire et stockage du courtier
line: "$CENTREONPLUGINS$/centreon_activemq_jmx.pl --plugin=apps::activemq::jmx::plugin --mode=broker-usage --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: app-apache
name: Apache HTTP Server
category: application
category: applications
status: verified
plugin: centreon_apache_serverstatus.pl
description: Supervision d'un serveur Apache via la page mod_status (charge CPU, requetes, slots, temps de reponse).
@@ -13,6 +13,21 @@ host_template:
- {name: APACHEPROTO, value: "http", description: "Protocole (http ou https)"}
- {name: APACHEURLPATH, value: "/server-status/?auto", description: "Chemin de la page mod_status"}
- {name: APACHEEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Apache
alias: Apache HTTP Server
notification:
perimetre: Apache HTTP Server
calendrier:
name: TP-App-Apache-24x7
modele: 24x7
alias: Apache HTTP Server, en permanence
groupe: CG-App-Apache
criticite: Majeure
impact: "Sites et applications web indisponibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu-Load
alias: Cpu-Load
+38
View File
@@ -0,0 +1,38 @@
id: app-dhcp-snmp
name: Microsoft DHCP (SNMP)
category: applications
status: to-verify
plugin: centreon_microsoft_dhcp_snmp.pl
description: Supervision d'un serveur DHCP Microsoft en SNMP (occupation des etendues).
host_template:
name: App-DHCP-SNMP-custom
alias: Applicatif Microsoft DHCP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-DHCP-SNMP
alias: Microsoft DHCP (SNMP)
notification:
perimetre: Microsoft DHCP (SNMP)
calendrier:
name: TP-App-DHCP-SNMP-24x7
modele: 24x7
alias: Microsoft DHCP (SNMP), en permanence
groupe: CG-App-DHCP-SNMP
criticite: Critique
impact: "Attribution d'adresses interrompue, postes sans reseau"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Subnet-Usage
alias: Subnet-Usage
description: Occupation des etendues
line: "$CENTREONPLUGINS$/centreon_microsoft_dhcp_snmp.pl --plugin=apps::microsoft::dhcp::snmp::plugin --mode=subnet-usage --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -0,0 +1,58 @@
id: app-elasticsearch
name: Elasticsearch
category: applications
status: to-verify
plugin: centreon_elasticsearch_restapi.pl
description: Supervision d'un cluster Elasticsearch via son API REST (sante du cluster, noeuds, index).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
notes: |
Un compte disposant du role monitoring suffit si la securite est activee.
host_template:
name: App-Elasticsearch-custom
alias: Applicatif Elasticsearch
parents: [generic-active-host-custom]
macros:
- {name: ESPORT, value: "9200", description: "Port de l'API"}
- {name: ESPROTO, value: "http", description: "Protocole d'acces"}
- {name: ESUSERNAME, value: "", description: "Compte de supervision"}
- {name: ESPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: ESEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Elasticsearch
alias: Elasticsearch
notification:
perimetre: Elasticsearch
calendrier:
name: TP-App-Elasticsearch-24x7
modele: 24x7
alias: Elasticsearch, en permanence
groupe: CG-App-Elasticsearch
criticite: Majeure
impact: "Recherche et journalisation degradees"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cluster-Status
alias: Cluster-Status
description: Sante globale du cluster
line: "$CENTREONPLUGINS$/centreon_elasticsearch_restapi.pl --plugin=apps::elasticsearch::restapi::plugin --mode=cluster-status --hostname=$HOSTADDRESS$ --port='$_HOSTESPORT$' --proto='$_HOSTESPROTO$' --api-username='$_HOSTESUSERNAME$' --api-password='$_HOSTESPASSWORD$' $_HOSTESEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Node-Statistics
alias: Node-Statistics
description: Consommation des noeuds du cluster
line: "$CENTREONPLUGINS$/centreon_elasticsearch_restapi.pl --plugin=apps::elasticsearch::restapi::plugin --mode=node-statistics --hostname=$HOSTADDRESS$ --port='$_HOSTESPORT$' --proto='$_HOSTESPROTO$' --api-username='$_HOSTESUSERNAME$' --api-password='$_HOSTESPASSWORD$' $_HOSTESEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Indices-Statistics
alias: Indices-Statistics
description: Taille et nombre de documents des index
default: false
line: "$CENTREONPLUGINS$/centreon_elasticsearch_restapi.pl --plugin=apps::elasticsearch::restapi::plugin --mode=indices-statistics --hostname=$HOSTADDRESS$ --port='$_HOSTESPORT$' --proto='$_HOSTESPROTO$' --api-username='$_HOSTESUSERNAME$' --api-password='$_HOSTESPASSWORD$' --filter-name='$_SERVICEFILTERNAME$' $_HOSTESEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: FILTERNAME, value: "", description: "Filtre sur le nom de l'index"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+41
View File
@@ -0,0 +1,41 @@
id: app-grafana
name: Grafana
category: applications
status: to-verify
plugin: centreon_grafana_restapi.pl
description: Supervision d'un serveur Grafana via son API REST (etat de fonctionnement).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
host_template:
name: App-Grafana-custom
alias: Applicatif Grafana
parents: [generic-active-host-custom]
macros:
- {name: APIPORT, value: "443", description: "Port de l'API"}
- {name: APIPROTO, value: "https", description: "Protocole d'acces"}
- {name: APITOKEN, value: "", description: "Jeton d'API", is_password: true}
- {name: APIEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Grafana
alias: Grafana
notification:
perimetre: Grafana
calendrier:
name: TP-App-Grafana-24x7
modele: 24x7
alias: Grafana, en permanence
groupe: CG-App-Grafana
criticite: Mineure
impact: "Tableaux de bord indisponibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Health
alias: Health
description: Etat de fonctionnement du serveur
line: "$CENTREONPLUGINS$/centreon_grafana_restapi.pl --plugin=apps::grafana::restapi::plugin --mode=health --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-token='$_HOSTAPITOKEN$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+50
View File
@@ -0,0 +1,50 @@
id: app-graylog
name: Graylog
category: applications
status: to-verify
plugin: centreon_graylog_restapi.pl
description: Supervision d'un serveur Graylog via son API REST (notifications, recherches).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
host_template:
name: App-Graylog-custom
alias: Applicatif Graylog
parents: [generic-active-host-custom]
macros:
- {name: APIPORT, value: "443", description: "Port de l'API"}
- {name: APIPROTO, value: "https", description: "Protocole d'acces"}
- {name: APIUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: APIPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: APIEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Graylog
alias: Graylog
notification:
perimetre: Graylog
calendrier:
name: TP-App-Graylog-24x7
modele: 24x7
alias: Graylog, en permanence
groupe: CG-App-Graylog
criticite: Majeure
impact: "Collecte et recherche de journaux interrompues"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Notifications
alias: Notifications
description: Notifications systeme du cluster
line: "$CENTREONPLUGINS$/centreon_graylog_restapi.pl --plugin=apps::graylog::restapi::plugin --mode=notifications --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-username='$_HOSTAPIUSERNAME$' --api-password='$_HOSTAPIPASSWORD$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Query
alias: Query
description: Nombre de messages correspondant a une recherche
line: "$CENTREONPLUGINS$/centreon_graylog_restapi.pl --plugin=apps::graylog::restapi::plugin --mode=query --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-username='$_HOSTAPIUSERNAME$' --api-password='$_HOSTAPIPASSWORD$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+46
View File
@@ -0,0 +1,46 @@
id: app-haproxy-snmp
name: HAProxy (SNMP)
category: applications
status: to-verify
plugin: centreon_haproxy_snmp.pl
description: Supervision d'un repartiteur HAProxy en SNMP (frontaux, arrieres, sessions).
host_template:
name: App-HAProxy-SNMP-custom
alias: Applicatif HAProxy SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-HAProxy-SNMP
alias: HAProxy (SNMP)
notification:
perimetre: HAProxy (SNMP)
calendrier:
name: TP-App-HAProxy-SNMP-24x7
modele: 24x7
alias: HAProxy (SNMP), en permanence
groupe: CG-App-HAProxy-SNMP
criticite: Critique
impact: "Repartition de charge degradee, services web inaccessibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Frontend-Usage
alias: Frontend-Usage
description: Sessions et trafic des frontaux
line: "$CENTREONPLUGINS$/centreon_haproxy_snmp.pl --plugin=apps::haproxy::snmp::plugin --mode=frontend-usage --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Backend-Usage
alias: Backend-Usage
description: Sessions et etat des arrieres
line: "$CENTREONPLUGINS$/centreon_haproxy_snmp.pl --plugin=apps::haproxy::snmp::plugin --mode=backend-usage --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -0,0 +1,49 @@
id: app-hashicorp-vault
name: HashiCorp Vault
category: applications
status: to-verify
plugin: centreon_hashicorp_vault_restapi.pl
description: Supervision d'un serveur HashiCorp Vault via son API REST (scellement, stockage Raft).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
host_template:
name: App-Vault-custom
alias: Applicatif HashiCorp Vault
parents: [generic-active-host-custom]
macros:
- {name: APIPORT, value: "443", description: "Port de l'API"}
- {name: APIPROTO, value: "https", description: "Protocole d'acces"}
- {name: APITOKEN, value: "", description: "Jeton d'API", is_password: true}
- {name: APIEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Vault
alias: HashiCorp Vault
notification:
perimetre: HashiCorp Vault
calendrier:
name: TP-App-Vault-24x7
modele: 24x7
alias: HashiCorp Vault, en permanence
groupe: CG-App-Vault
criticite: Critique
impact: "Secrets inaccessibles, applications dependantes bloquees"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Seal-Status
alias: Seal-Status
description: Etat de scellement du coffre
line: "$CENTREONPLUGINS$/centreon_hashicorp_vault_restapi.pl --plugin=apps::hashicorp::vault::restapi::plugin --mode=seal-status --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-token='$_HOSTAPITOKEN$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Raft-Storage
alias: Raft-Storage
description: Performances du stockage Raft
line: "$CENTREONPLUGINS$/centreon_hashicorp_vault_restapi.pl --plugin=apps::hashicorp::vault::restapi::plugin --mode=raft-storage --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-token='$_HOSTAPITOKEN$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+50
View File
@@ -0,0 +1,50 @@
id: app-iis-restapi
name: Microsoft IIS (API REST)
category: applications
status: to-verify
plugin: centreon_iis_restapi.pl
description: Supervision d'un serveur IIS via l'API REST de l'administration (pools, sites).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
host_template:
name: App-IIS-custom
alias: Applicatif Microsoft IIS
parents: [generic-active-host-custom]
macros:
- {name: APIPORT, value: "443", description: "Port de l'API"}
- {name: APIPROTO, value: "https", description: "Protocole d'acces"}
- {name: APIUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: APIPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: APIEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-IIS
alias: Microsoft IIS (API REST)
notification:
perimetre: Microsoft IIS (API REST)
calendrier:
name: TP-App-IIS-24x7
modele: 24x7
alias: Microsoft IIS (API REST), en permanence
groupe: CG-App-IIS
criticite: Majeure
impact: "Sites et applications web indisponibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Application-Pools
alias: Application-Pools
description: Etat des pools d'applications
line: "$CENTREONPLUGINS$/centreon_iis_restapi.pl --plugin=apps::microsoft::iis::restapi::plugin --mode=application-pools --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-username='$_HOSTAPIUSERNAME$' --api-password='$_HOSTAPIPASSWORD$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Web-Sites
alias: Web-Sites
description: Trafic et connexions des sites
line: "$CENTREONPLUGINS$/centreon_iis_restapi.pl --plugin=apps::microsoft::iis::restapi::plugin --mode=web-sites --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-username='$_HOSTAPIUSERNAME$' --api-password='$_HOSTAPIPASSWORD$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+49
View File
@@ -0,0 +1,49 @@
id: app-jenkins
name: Jenkins
category: applications
status: to-verify
plugin: centreon_jenkins_restapi.pl
description: Supervision d'un serveur Jenkins via son API REST (etat des travaux).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
host_template:
name: App-Jenkins-custom
alias: Applicatif Jenkins
parents: [generic-active-host-custom]
macros:
- {name: APIPORT, value: "443", description: "Port de l'API"}
- {name: APIPROTO, value: "https", description: "Protocole d'acces"}
- {name: APITOKEN, value: "", description: "Jeton d'API", is_password: true}
- {name: APIEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Jenkins
alias: Jenkins
notification:
perimetre: Jenkins
calendrier:
name: TP-App-Jenkins-24x7
modele: 24x7
alias: Jenkins, en permanence
groupe: CG-App-Jenkins
criticite: Mineure
impact: "Chaines d'integration continue a l'arret"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Jobs
alias: Jobs
description: Etat des travaux
line: "$CENTREONPLUGINS$/centreon_jenkins_restapi.pl --plugin=apps::jenkins::restapi::plugin --mode=jobs --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-token='$_HOSTAPITOKEN$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Nodes
alias: Nodes
description: Etat des agents de construction
line: "$CENTREONPLUGINS$/centreon_jenkins_restapi.pl --plugin=apps::jenkins::restapi::plugin --mode=nodes --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-token='$_HOSTAPITOKEN$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+70
View File
@@ -0,0 +1,70 @@
id: app-jvm-jmx
name: Machine virtuelle Java (JMX)
category: applications
status: to-verify
plugin: centreon_java_jvm.pl
description: Supervision d'une machine virtuelle Java via JMX et l'agent Jolokia.
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
notes: |
Deployer l'agent Jolokia dans la JVM supervisee et exposer son point
d'acces au collecteur : les plugins JMX de Centreon passent par lui.
host_template:
name: App-JVM-JMX-custom
alias: Applicatif JVM JMX
parents: [generic-active-host-custom]
macros:
- {name: JMXURL, value: "http://localhost:8080/jolokia", description: "URL de l'agent Jolokia"}
- {name: JMXUSERNAME, value: "", description: "Compte Jolokia"}
- {name: JMXPASSWORD, value: "", description: "Mot de passe Jolokia", is_password: true}
- {name: JMXEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-JVM-JMX
alias: Machine virtuelle Java (JMX)
notification:
perimetre: Machine virtuelle Java (JMX)
calendrier:
name: TP-App-JVM-JMX-24x7
modele: 24x7
alias: Machine virtuelle Java (JMX), en permanence
groupe: CG-App-JVM-JMX
criticite: Majeure
impact: "Application Java degradee ou arretee"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Memory
alias: Memory
description: Memoire utilisee par la JVM
line: "$CENTREONPLUGINS$/centreon_java_jvm.pl --plugin=apps::java::jvm::plugin --mode=memory --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Gc
alias: Gc
description: Ramasse-miettes
line: "$CENTREONPLUGINS$/centreon_java_jvm.pl --plugin=apps::java::jvm::plugin --mode=gcutil --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Threads
alias: Threads
description: Fils d'execution
line: "$CENTREONPLUGINS$/centreon_java_jvm.pl --plugin=apps::java::jvm::plugin --mode=threads --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Class-Count
alias: Class-Count
description: Classes chargees
line: "$CENTREONPLUGINS$/centreon_java_jvm.pl --plugin=apps::java::jvm::plugin --mode=class-count --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+62
View File
@@ -0,0 +1,62 @@
id: app-kafka-jmx
name: Apache Kafka (JMX)
category: applications
status: to-verify
plugin: centreon_kafka_jmx.pl
description: Supervision d'un courtier Kafka via JMX et l'agent Jolokia.
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
notes: |
Deployer l'agent Jolokia dans la JVM supervisee et exposer son point
d'acces au collecteur : les plugins JMX de Centreon passent par lui.
host_template:
name: App-Kafka-JMX-custom
alias: Applicatif Kafka JMX
parents: [generic-active-host-custom]
macros:
- {name: JMXURL, value: "http://localhost:8080/jolokia", description: "URL de l'agent Jolokia"}
- {name: JMXUSERNAME, value: "", description: "Compte Jolokia"}
- {name: JMXPASSWORD, value: "", description: "Mot de passe Jolokia", is_password: true}
- {name: JMXEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Kafka-JMX
alias: Apache Kafka (JMX)
notification:
perimetre: Apache Kafka (JMX)
calendrier:
name: TP-App-Kafka-JMX-24x7
modele: 24x7
alias: Apache Kafka (JMX), en permanence
groupe: CG-App-Kafka-JMX
criticite: Majeure
impact: "Echanges entre applications interrompus"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Broker-Status
alias: Broker-Status
description: Etat du courtier et partitions
line: "$CENTREONPLUGINS$/centreon_kafka_jmx.pl --plugin=apps::kafka::jmx::plugin --mode=brokers --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Topics
alias: Topics
description: Trafic par sujet
line: "$CENTREONPLUGINS$/centreon_kafka_jmx.pl --plugin=apps::kafka::jmx::plugin --mode=topics --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Global
alias: Global
description: Statistiques globales du cluster
line: "$CENTREONPLUGINS$/centreon_kafka_jmx.pl --plugin=apps::kafka::jmx::plugin --mode=global --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -0,0 +1,36 @@
id: app-keepalived-snmp
name: Keepalived (SNMP)
category: applications
status: to-verify
plugin: centreon_keepalived_snmp.pl
description: Supervision de l'etat VRRP d'un noeud Keepalived en SNMP.
host_template:
name: App-Keepalived-SNMP-custom
alias: Applicatif Keepalived SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Keepalived-SNMP
alias: Keepalived (SNMP)
notification:
perimetre: Keepalived (SNMP)
calendrier:
name: TP-App-Keepalived-SNMP-24x7
modele: 24x7
alias: Keepalived (SNMP), en permanence
groupe: CG-App-Keepalived-SNMP
criticite: Critique
impact: "Bascule d'adresse virtuelle compromise"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Vrrp-Status
alias: Vrrp-Status
description: Etat des instances VRRP
line: "$CENTREONPLUGINS$/centreon_keepalived_snmp.pl --plugin=apps::keepalived::snmp::plugin --mode=vrrp-status --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: app-nginx
name: Nginx
category: application
category: applications
status: verified
plugin: centreon_nginx_serverstatus.pl
description: Supervision d'un serveur Nginx via le module stub_status (connexions, requetes, temps de reponse).
@@ -13,6 +13,21 @@ host_template:
- {name: NGINXPROTO, value: "http", description: "Protocole (http ou https)"}
- {name: NGINXURLPATH, value: "/nginx_status", description: "Chemin de la page stub_status"}
- {name: NGINXEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Nginx
alias: Nginx
notification:
perimetre: Nginx
calendrier:
name: TP-App-Nginx-24x7
modele: 24x7
alias: Nginx, en permanence
groupe: CG-App-Nginx
criticite: Majeure
impact: "Sites et applications web indisponibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Connections
alias: Connections
+54
View File
@@ -0,0 +1,54 @@
id: app-php-fpm
name: PHP-FPM
category: applications
status: to-verify
plugin: centreon_php_fpm_web.pl
description: Supervision d'un pool PHP-FPM via sa page de statut (processus, file d'attente, requetes).
prerequis:
paquets:
debian: [libwww-perl]
rhel: [perl-libwww-perl]
notes: |
Activer pm.status_path dans la configuration du pool, et exposer ce chemin
au collecteur depuis le serveur web.
host_template:
name: App-PHP-FPM-custom
alias: Applicatif PHP-FPM
parents: [generic-active-host-custom]
macros:
- {name: FPMPORT, value: "80", description: "Port du serveur web"}
- {name: FPMPROTO, value: "http", description: "Protocole d'acces"}
- {name: FPMURLPATH, value: "/status", description: "Chemin de la page de statut"}
- {name: FPMEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-PHP-FPM
alias: PHP-FPM
notification:
perimetre: PHP-FPM
calendrier:
name: TP-App-PHP-FPM-24x7
modele: 24x7
alias: PHP-FPM, en permanence
groupe: CG-App-PHP-FPM
criticite: Majeure
impact: "Applications PHP indisponibles ou saturees"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Processes
alias: Processes
description: Processus actifs, inactifs et file d'attente
line: "$CENTREONPLUGINS$/centreon_php_fpm_web.pl --plugin=apps::php::fpm::web::plugin --mode=usage --hostname=$HOSTADDRESS$ --port='$_HOSTFPMPORT$' --proto='$_HOSTFPMPROTO$' --urlpath='$_HOSTFPMURLPATH$' --warning-active-processes='$_SERVICEWARNING$' --critical-active-processes='$_SERVICECRITICAL$' $_HOSTFPMEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning sur les processus actifs"}
- {name: CRITICAL, value: "", description: "Seuil critical sur les processus actifs"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Listen-Queue
alias: Listen-Queue
description: File d'attente des connexions
line: "$CENTREONPLUGINS$/centreon_php_fpm_web.pl --plugin=apps::php::fpm::web::plugin --mode=usage --hostname=$HOSTADDRESS$ --port='$_HOSTFPMPORT$' --proto='$_HOSTFPMPROTO$' --urlpath='$_HOSTFPMURLPATH$' --warning-listen-queue='$_SERVICEWARNING$' --critical-listen-queue='$_SERVICECRITICAL$' $_HOSTFPMEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "1", description: "Seuil warning sur la file d'attente"}
- {name: CRITICAL, value: "10", description: "Seuil critical sur la file d'attente"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+43
View File
@@ -0,0 +1,43 @@
id: app-prometheus
name: Prometheus
category: applications
status: to-verify
plugin: centreon_prometheus_api.pl
description: Supervision d'un serveur Prometheus via son API REST (cibles).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
host_template:
name: App-Prometheus-custom
alias: Applicatif Prometheus
parents: [generic-active-host-custom]
macros:
- {name: APIPORT, value: "443", description: "Port de l'API"}
- {name: APIPROTO, value: "https", description: "Protocole d'acces"}
- {name: APITOKEN, value: "", description: "Jeton d'API", is_password: true}
- {name: APIEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Prometheus
alias: Prometheus
notification:
perimetre: Prometheus
calendrier:
name: TP-App-Prometheus-24x7
modele: 24x7
alias: Prometheus, en permanence
groupe: CG-App-Prometheus
criticite: Mineure
impact: "Collecte de metriques interrompue"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Targets
alias: Targets
description: Etat des cibles de collecte
line: "$CENTREONPLUGINS$/centreon_prometheus_api.pl --plugin=cloud::prometheus::restapi::plugin --mode=targets --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-token='$_HOSTAPITOKEN$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+61
View File
@@ -0,0 +1,61 @@
id: app-rabbitmq
name: RabbitMQ
category: applications
status: to-verify
plugin: centreon_rabbitmq_restapi.pl
description: Supervision d'un broker RabbitMQ via son API de management (files, noeuds, connexions).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
notes: |
Activer le plugin de management, puis creer un compte avec le tag monitoring :
rabbitmqctl add_user centreon '...'
rabbitmqctl set_user_tags centreon monitoring
host_template:
name: App-RabbitMQ-custom
alias: Applicatif RabbitMQ
parents: [generic-active-host-custom]
macros:
- {name: RABBITPORT, value: "15672", description: "Port de l'API de management"}
- {name: RABBITUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: RABBITPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: RABBITEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-RabbitMQ
alias: RabbitMQ
notification:
perimetre: RabbitMQ
calendrier:
name: TP-App-RabbitMQ-24x7
modele: 24x7
alias: RabbitMQ, en permanence
groupe: CG-App-RabbitMQ
criticite: Majeure
impact: "Echanges entre applications interrompus"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Node-Usage
alias: Node-Usage
description: Etat et consommation des noeuds
line: "$CENTREONPLUGINS$/centreon_rabbitmq_restapi.pl --plugin=apps::rabbitmq::restapi::plugin --mode=node-usage --hostname=$HOSTADDRESS$ --port='$_HOSTRABBITPORT$' --api-username='$_HOSTRABBITUSERNAME$' --api-password='$_HOSTRABBITPASSWORD$' $_HOSTRABBITEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Queue-Usage
alias: Queue-Usage
description: Messages en attente dans les files
line: "$CENTREONPLUGINS$/centreon_rabbitmq_restapi.pl --plugin=apps::rabbitmq::restapi::plugin --mode=queue-usage --hostname=$HOSTADDRESS$ --port='$_HOSTRABBITPORT$' --api-username='$_HOSTRABBITUSERNAME$' --api-password='$_HOSTRABBITPASSWORD$' --filter-name='$_SERVICEFILTERNAME$' --warning-messages-ready='$_SERVICEWARNING$' --critical-messages-ready='$_SERVICECRITICAL$' $_HOSTRABBITEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: FILTERNAME, value: "", description: "Filtre sur le nom de la file"}
- {name: WARNING, value: "1000", description: "Seuil warning sur les messages en attente"}
- {name: CRITICAL, value: "5000", description: "Seuil critical sur les messages en attente"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Connections
alias: Connections
description: Connexions et canaux ouverts
default: false
line: "$CENTREONPLUGINS$/centreon_rabbitmq_restapi.pl --plugin=apps::rabbitmq::restapi::plugin --mode=connections --hostname=$HOSTADDRESS$ --port='$_HOSTRABBITPORT$' --api-username='$_HOSTRABBITUSERNAME$' --api-password='$_HOSTRABBITPASSWORD$' $_HOSTRABBITEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+54
View File
@@ -0,0 +1,54 @@
id: app-squid-snmp
name: Squid (SNMP)
category: applications
status: to-verify
plugin: centreon_squid_snmp.pl
description: Supervision d'un mandataire Squid en SNMP (cache, trafic, ressources).
host_template:
name: App-Squid-SNMP-custom
alias: Applicatif Squid SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Squid-SNMP
alias: Squid (SNMP)
notification:
perimetre: Squid (SNMP)
calendrier:
name: TP-App-Squid-SNMP-24x7
modele: 24x7
alias: Squid (SNMP), en permanence
groupe: CG-App-Squid-SNMP
criticite: Majeure
impact: "Acces web des postes bloque ou ralenti"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cache-Usage
alias: Cache-Usage
description: Taux de succes et occupation du cache
line: "$CENTREONPLUGINS$/centreon_squid_snmp.pl --plugin=apps::squid::snmp::plugin --mode=cache-usage --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Traffic
alias: Traffic
description: Trafic HTTP et ICP
line: "$CENTREONPLUGINS$/centreon_squid_snmp.pl --plugin=apps::squid::snmp::plugin --mode=traffic --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: System
alias: System
description: Processeur et memoire du service
line: "$CENTREONPLUGINS$/centreon_squid_snmp.pl --plugin=apps::squid::snmp::plugin --mode=system --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+70
View File
@@ -0,0 +1,70 @@
id: app-tomcat-jmx
name: Apache Tomcat (JMX)
category: applications
status: to-verify
plugin: centreon_tomcat_jmx.pl
description: Supervision d'un serveur Tomcat via JMX et l'agent Jolokia.
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
notes: |
Deployer l'agent Jolokia dans la JVM supervisee et exposer son point
d'acces au collecteur : les plugins JMX de Centreon passent par lui.
host_template:
name: App-Tomcat-JMX-custom
alias: Applicatif Tomcat JMX
parents: [generic-active-host-custom]
macros:
- {name: JMXURL, value: "http://localhost:8080/jolokia", description: "URL de l'agent Jolokia"}
- {name: JMXUSERNAME, value: "", description: "Compte Jolokia"}
- {name: JMXPASSWORD, value: "", description: "Mot de passe Jolokia", is_password: true}
- {name: JMXEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Tomcat-JMX
alias: Apache Tomcat (JMX)
notification:
perimetre: Apache Tomcat (JMX)
calendrier:
name: TP-App-Tomcat-JMX-24x7
modele: 24x7
alias: Apache Tomcat (JMX), en permanence
groupe: CG-App-Tomcat-JMX
criticite: Majeure
impact: "Applications Java hebergees indisponibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Memory
alias: Memory
description: Memoire de la JVM
line: "$CENTREONPLUGINS$/centreon_tomcat_jmx.pl --plugin=apps::tomcat::jmx::plugin --mode=memory-detailed --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Threads
alias: Threads
description: Fils d'execution
line: "$CENTREONPLUGINS$/centreon_tomcat_jmx.pl --plugin=apps::tomcat::jmx::plugin --mode=threads --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Sessions
alias: Sessions
description: Sessions des applications web
line: "$CENTREONPLUGINS$/centreon_tomcat_jmx.pl --plugin=apps::tomcat::jmx::plugin --mode=sessions --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Requests
alias: Requests
description: Requetes traitees par les connecteurs
line: "$CENTREONPLUGINS$/centreon_tomcat_jmx.pl --plugin=apps::tomcat::jmx::plugin --mode=connector-usage --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+50
View File
@@ -0,0 +1,50 @@
id: app-veeam-vbem
name: Veeam Backup Enterprise Manager
category: applications
status: to-verify
plugin: centreon_veeam_vbem_restapi.pl
description: Supervision de Veeam Backup Enterprise Manager via son API REST (travaux, depots).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
host_template:
name: App-Veeam-VBEM-custom
alias: Applicatif Veeam Enterprise Manager
parents: [generic-active-host-custom]
macros:
- {name: APIPORT, value: "443", description: "Port de l'API"}
- {name: APIPROTO, value: "https", description: "Protocole d'acces"}
- {name: APIUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: APIPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: APIEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Veeam-VBEM
alias: Veeam Backup Enterprise Manager
notification:
perimetre: Veeam Backup Enterprise Manager
calendrier:
name: TP-App-Veeam-VBEM-24x7
modele: 24x7
alias: Veeam Backup Enterprise Manager, en permanence
groupe: CG-App-Veeam-VBEM
criticite: Critique
impact: "Sauvegardes non verifiees, restauration compromise"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Job-Status
alias: Job-Status
description: Etat des travaux de sauvegarde
line: "$CENTREONPLUGINS$/centreon_veeam_vbem_restapi.pl --plugin=apps::backup::veeam::vbem::restapi::plugin --mode=job-status --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-username='$_HOSTAPIUSERNAME$' --api-password='$_HOSTAPIPASSWORD$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Repository-Usage
alias: Repository-Usage
description: Occupation des depots
line: "$CENTREONPLUGINS$/centreon_veeam_vbem_restapi.pl --plugin=apps::backup::veeam::vbem::restapi::plugin --mode=repository-usage --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-username='$_HOSTAPIUSERNAME$' --api-password='$_HOSTAPIPASSWORD$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+50
View File
@@ -0,0 +1,50 @@
id: app-wazuh
name: Wazuh
category: applications
status: to-verify
plugin: centreon_wazuh_restapi.pl
description: Supervision d'un gestionnaire Wazuh via son API REST (agents, processus).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
host_template:
name: App-Wazuh-custom
alias: Applicatif Wazuh
parents: [generic-active-host-custom]
macros:
- {name: APIPORT, value: "443", description: "Port de l'API"}
- {name: APIPROTO, value: "https", description: "Protocole d'acces"}
- {name: APIUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: APIPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: APIEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Wazuh
alias: Wazuh
notification:
perimetre: Wazuh
calendrier:
name: TP-App-Wazuh-24x7
modele: 24x7
alias: Wazuh, en permanence
groupe: CG-App-Wazuh
criticite: Critique
impact: "Detection d'intrusion et conformite hors service"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Agents
alias: Agents
description: Etat de connexion des agents
line: "$CENTREONPLUGINS$/centreon_wazuh_restapi.pl --plugin=apps::wazuh::restapi::plugin --mode=agents --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-username='$_HOSTAPIUSERNAME$' --api-password='$_HOSTAPIPASSWORD$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Manager
alias: Manager
description: Processus du gestionnaire
line: "$CENTREONPLUGINS$/centreon_wazuh_restapi.pl --plugin=apps::wazuh::restapi::plugin --mode=manager --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-username='$_HOSTAPIUSERNAME$' --api-password='$_HOSTAPIPASSWORD$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -0,0 +1,62 @@
id: app-zookeeper-jmx
name: Apache ZooKeeper (JMX)
category: applications
status: to-verify
plugin: centreon_zookeeper_jmx.pl
description: Supervision d'un noeud ZooKeeper via JMX et l'agent Jolokia.
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
notes: |
Deployer l'agent Jolokia dans la JVM supervisee et exposer son point
d'acces au collecteur : les plugins JMX de Centreon passent par lui.
host_template:
name: App-ZooKeeper-JMX-custom
alias: Applicatif ZooKeeper JMX
parents: [generic-active-host-custom]
macros:
- {name: JMXURL, value: "http://localhost:8080/jolokia", description: "URL de l'agent Jolokia"}
- {name: JMXUSERNAME, value: "", description: "Compte Jolokia"}
- {name: JMXPASSWORD, value: "", description: "Mot de passe Jolokia", is_password: true}
- {name: JMXEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-ZooKeeper-JMX
alias: Apache ZooKeeper (JMX)
notification:
perimetre: Apache ZooKeeper (JMX)
calendrier:
name: TP-App-ZooKeeper-JMX-24x7
modele: 24x7
alias: Apache ZooKeeper (JMX), en permanence
groupe: CG-App-ZooKeeper-JMX
criticite: Majeure
impact: "Coordination du cluster perdue"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Connections
alias: Connections
description: Connexions clientes
line: "$CENTREONPLUGINS$/centreon_zookeeper_jmx.pl --plugin=apps::zookeeper::jmx::plugin --mode=connections --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Latency
alias: Latency
description: Latence des requetes
line: "$CENTREONPLUGINS$/centreon_zookeeper_jmx.pl --plugin=apps::zookeeper::jmx::plugin --mode=latency --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Packets
alias: Packets
description: Paquets emis et recus
line: "$CENTREONPLUGINS$/centreon_zookeeper_jmx.pl --plugin=apps::zookeeper::jmx::plugin --mode=packets --url='$_HOSTJMXURL$' --username='$_HOSTJMXUSERNAME$' --password='$_HOSTJMXPASSWORD$' $_HOSTJMXEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning"}
- {name: CRITICAL, value: "90", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+67
View File
@@ -0,0 +1,67 @@
id: app-mongodb
name: MongoDB
category: database
status: to-verify
plugin: centreon_mongodb.pl
description: Supervision d'une instance MongoDB (connexion, operations, taille des bases, replication).
prerequis:
paquets:
debian: [libmongodb-perl]
rhel: [perl-MongoDB]
notes: |
Compte de supervision avec le role clusterMonitor :
db.createUser({user: "centreon", pwd: "...", roles: [{role: "clusterMonitor", db: "admin"}]})
host_template:
name: App-MongoDB-custom
alias: Applicatif MongoDB
parents: [generic-active-host-custom]
macros:
- {name: MONGOPORT, value: "27017", description: "Port d'ecoute"}
- {name: MONGOUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: MONGOPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: MONGOEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-MongoDB
alias: MongoDB
notification:
perimetre: MongoDB
calendrier:
name: TP-App-MongoDB-24x7
modele: 24x7
alias: MongoDB, en permanence
groupe: CG-App-MongoDB
criticite: Majeure
impact: "Bases de donnees inaccessibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Connection-Time
alias: Connection-Time
description: Temps d'etablissement de la connexion
line: "$CENTREONPLUGINS$/centreon_mongodb.pl --plugin=database::mongodb::plugin --mode=connection-time --hostname=$HOSTADDRESS$ --port='$_HOSTMONGOPORT$' --username='$_HOSTMONGOUSERNAME$' --password='$_HOSTMONGOPASSWORD$' --warning='$_SERVICEWARNING$' --critical='$_SERVICECRITICAL$' $_HOSTMONGOEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "1000", description: "Seuil warning en ms"}
- {name: CRITICAL, value: "5000", description: "Seuil critical en ms"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Databases-Size
alias: Databases-Size
description: Taille des bases de donnees
line: "$CENTREONPLUGINS$/centreon_mongodb.pl --plugin=database::mongodb::plugin --mode=databases-size --hostname=$HOSTADDRESS$ --port='$_HOSTMONGOPORT$' --username='$_HOSTMONGOUSERNAME$' --password='$_HOSTMONGOPASSWORD$' $_HOSTMONGOEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Operations
alias: Operations
description: Operations par seconde
line: "$CENTREONPLUGINS$/centreon_mongodb.pl --plugin=database::mongodb::plugin --mode=operations --hostname=$HOSTADDRESS$ --port='$_HOSTMONGOPORT$' --username='$_HOSTMONGOUSERNAME$' --password='$_HOSTMONGOPASSWORD$' $_HOSTMONGOEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Replication-Lag
alias: Replication-Lag
description: Retard de replication du jeu de replicas
default: false
line: "$CENTREONPLUGINS$/centreon_mongodb.pl --plugin=database::mongodb::plugin --mode=replication-lag --hostname=$HOSTADDRESS$ --port='$_HOSTMONGOPORT$' --username='$_HOSTMONGOUSERNAME$' --password='$_HOSTMONGOPASSWORD$' --warning='$_SERVICEWARNING$' --critical='$_SERVICECRITICAL$' $_HOSTMONGOEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "60", description: "Retard warning en secondes"}
- {name: CRITICAL, value: "300", description: "Retard critical en secondes"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: app-mssql
name: Microsoft SQL Server
category: application
category: database
status: verified
plugin: centreon_mssql.pl
description: Supervision d'une instance SQL Server (connexion, taille des bases, sauvegardes, jobs, sessions, verrous).
@@ -13,6 +13,30 @@ host_template:
- {name: MSSQLUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: MSSQLPASSWORD, value: "", description: "Mot de passe du compte de supervision", is_password: true}
- {name: MSSQLEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
prerequis:
paquets:
debian: [libdbd-sybase-perl, freetds-bin]
rhel: [perl-DBD-Sybase, freetds]
notes: |
Le plugin passe par FreeTDS. Verifier /etc/freetds/freetds.conf et le
droit VIEW SERVER STATE pour le compte de supervision.
verifications:
- "/usr/lib/centreon/plugins/centreon_mssql.pl --plugin=database::mssql::plugin --list-mode"
groupe_hote:
name: HG-App-DB-MSSQL
alias: Microsoft SQL Server
notification:
perimetre: Microsoft SQL Server
calendrier:
name: TP-App-DB-MSSQL-24x7
modele: 24x7
alias: Microsoft SQL Server, en permanence
groupe: CG-App-DB-MSSQL
criticite: Majeure
impact: "Bases de donnees inaccessibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Connection-Time
alias: Connection-Time
@@ -1,6 +1,6 @@
id: app-mysql
name: MySQL / MariaDB
category: application
category: database
status: verified
plugin: centreon_mysql.pl
description: Supervision d'une instance MySQL ou MariaDB (connexion, requetes, threads, replication, taille des bases).
@@ -13,6 +13,31 @@ host_template:
- {name: MYSQLUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: MYSQLPASSWORD, value: "", description: "Mot de passe du compte de supervision", is_password: true}
- {name: MYSQLEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
prerequis:
paquets:
debian: [libdbd-mysql-perl]
rhel: [perl-DBD-MySQL]
notes: |
Creer un compte de supervision en lecture seule sur l'instance :
CREATE USER 'centreon'@'%' IDENTIFIED BY '...';
GRANT REPLICATION CLIENT, PROCESS, SELECT ON *.* TO 'centreon'@'%';
verifications:
- "/usr/lib/centreon/plugins/centreon_mysql.pl --plugin=database::mysql::plugin --list-mode"
groupe_hote:
name: HG-App-DB-MySQL
alias: MySQL / MariaDB
notification:
perimetre: MySQL / MariaDB
calendrier:
name: TP-App-DB-MySQL-24x7
modele: 24x7
alias: MySQL / MariaDB, en permanence
groupe: CG-App-DB-MySQL
criticite: Majeure
impact: "Bases de donnees inaccessibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Connection-Time
alias: Connection-Time
@@ -1,6 +1,6 @@
id: app-oracle
name: Oracle Database
category: application
category: database
status: to-verify
plugin: centreon_oracle.pl
description: Supervision d'une instance Oracle (connexion, tablespaces, sessions, processus, sauvegardes RMAN). Necessite un client Oracle sur le collecteur.
@@ -14,6 +14,28 @@ host_template:
- {name: ORACLEUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: ORACLEPASSWORD, value: "", description: "Mot de passe du compte de supervision", is_password: true}
- {name: ORACLEEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
prerequis:
notes: |
Necessite le client Oracle Instant Client et le module Perl DBD::Oracle,
tous deux absents des depots standards : suivre la procedure Oracle, puis
definir ORACLE_HOME et LD_LIBRARY_PATH pour l'utilisateur centreon-engine.
verifications:
- "/usr/lib/centreon/plugins/centreon_oracle.pl --plugin=database::oracle::plugin --list-mode"
groupe_hote:
name: HG-App-DB-Oracle
alias: Oracle Database
notification:
perimetre: Oracle Database
calendrier:
name: TP-App-DB-Oracle-24x7
modele: 24x7
alias: Oracle Database, en permanence
groupe: CG-App-DB-Oracle
criticite: Majeure
impact: "Bases de donnees inaccessibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Connection-Time
alias: Connection-Time
@@ -1,6 +1,6 @@
id: app-postgresql
name: PostgreSQL
category: application
category: database
status: verified
plugin: centreon_postgres.pl
description: Supervision d'une instance PostgreSQL (connexion, sessions, taille des bases, verrous, temps de requete).
@@ -14,6 +14,31 @@ host_template:
- {name: PGPASSWORD, value: "", description: "Mot de passe du compte de supervision", is_password: true}
- {name: PGDATABASE, value: "postgres", description: "Base de connexion"}
- {name: PGEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
prerequis:
paquets:
debian: [libdbd-pg-perl]
rhel: [perl-DBD-Pg]
notes: |
Compte de supervision avec le role pg_monitor :
CREATE ROLE centreon LOGIN PASSWORD '...';
GRANT pg_monitor TO centreon;
verifications:
- "/usr/lib/centreon/plugins/centreon_postgres.pl --plugin=database::postgres::plugin --list-mode"
groupe_hote:
name: HG-App-DB-PostgreSQL
alias: PostgreSQL
notification:
perimetre: PostgreSQL
calendrier:
name: TP-App-DB-PostgreSQL-24x7
modele: 24x7
alias: PostgreSQL, en permanence
groupe: CG-App-DB-PostgreSQL
criticite: Majeure
impact: "Bases de donnees inaccessibles"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Connection-Time
alias: Connection-Time
+66
View File
@@ -0,0 +1,66 @@
id: app-redis
name: Redis
category: database
status: to-verify
plugin: centreon_redis_cli.pl
description: Supervision d'une instance Redis (clients, memoire, persistance, replication).
prerequis:
paquets:
debian: [libredis-perl]
rhel: [perl-Redis]
notes: |
Un compte en lecture seule suffit. Avec Redis 6 et superieur, creer un utilisateur ACL
limite a la commande INFO plutot que d'utiliser le mot de passe principal.
host_template:
name: App-Redis-custom
alias: Applicatif Redis
parents: [generic-active-host-custom]
macros:
- {name: REDISPORT, value: "6379", description: "Port d'ecoute"}
- {name: REDISPASSWORD, value: "", description: "Mot de passe", is_password: true}
- {name: REDISEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Redis
alias: Redis
notification:
perimetre: Redis
calendrier:
name: TP-App-Redis-24x7
modele: 24x7
alias: Redis, en permanence
groupe: CG-App-Redis
criticite: Majeure
impact: "Cache applicatif indisponible, degradation des temps de reponse"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Clients
alias: Clients
description: Nombre de clients connectes
line: "$CENTREONPLUGINS$/centreon_redis_cli.pl --plugin=apps::redis::cli::plugin --mode=clients --server=$HOSTADDRESS$ --port='$_HOSTREDISPORT$' --password='$_HOSTREDISPASSWORD$' --warning-connected='$_SERVICEWARNING$' --critical-connected='$_SERVICECRITICAL$' $_HOSTREDISEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Memoire utilisee et fragmentation
line: "$CENTREONPLUGINS$/centreon_redis_cli.pl --plugin=apps::redis::cli::plugin --mode=memory --server=$HOSTADDRESS$ --port='$_HOSTREDISPORT$' --password='$_HOSTREDISPASSWORD$' --warning-memory-used='$_SERVICEWARNING$' --critical-memory-used='$_SERVICECRITICAL$' $_HOSTREDISEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning en octets"}
- {name: CRITICAL, value: "", description: "Seuil critical en octets"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Persistence
alias: Persistence
description: Etat des sauvegardes RDB et AOF
line: "$CENTREONPLUGINS$/centreon_redis_cli.pl --plugin=apps::redis::cli::plugin --mode=persistence --server=$HOSTADDRESS$ --port='$_HOSTREDISPORT$' --password='$_HOSTREDISPASSWORD$' $_HOSTREDISEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Replication
alias: Replication
description: Etat de la replication
default: false
line: "$CENTREONPLUGINS$/centreon_redis_cli.pl --plugin=apps::redis::cli::plugin --mode=replication --server=$HOSTADDRESS$ --port='$_HOSTREDISPORT$' --password='$_HOSTREDISPASSWORD$' $_HOSTREDISEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: hw-dell-idrac-snmp
name: Serveur Dell (iDRAC SNMP)
category: hardware
category: hardware-server
status: verified
plugin: centreon_dell_idrac_snmp.pl
description: Etat materiel d'un serveur Dell PowerEdge via la carte iDRAC en SNMP (global, alimentations, ventilateurs, temperatures, disques, memoire).
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Dell-iDRAC-SNMP
alias: Serveur Dell (iDRAC SNMP)
notification:
perimetre: Serveur Dell (iDRAC SNMP)
calendrier:
name: TP-HW-Dell-iDRAC-SNMP-24x7
modele: 24x7
alias: Serveur Dell (iDRAC SNMP), en permanence
groupe: CG-HW-Dell-iDRAC-SNMP
criticite: Majeure
impact: "Materiel serveur en defaut"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Hardware
alias: Hardware
@@ -1,6 +1,6 @@
id: hw-hp-proliant-snmp
name: Serveur HP ProLiant (iLO SNMP)
category: hardware
category: hardware-server
status: verified
plugin: centreon_hp_proliant_snmp.pl
description: Etat materiel d'un serveur HP ProLiant via les agents Insight / iLO en SNMP.
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-HP-Proliant-SNMP
alias: Serveur HP ProLiant (iLO SNMP)
notification:
perimetre: Serveur HP ProLiant (iLO SNMP)
calendrier:
name: TP-HW-HP-Proliant-SNMP-24x7
modele: 24x7
alias: Serveur HP ProLiant (iLO SNMP), en permanence
groupe: CG-HW-HP-Proliant-SNMP
criticite: Majeure
impact: "Materiel serveur en defaut"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Hardware
alias: Hardware
@@ -0,0 +1,71 @@
id: hw-alcatel-omniswitch-snmp
name: Switch Alcatel OmniSwitch (SNMP)
category: network
status: to-verify
plugin: centreon_alcatel_omniswitch_snmp.pl
description: Supervision d'un commutateur Alcatel-Lucent OmniSwitch en SNMP.
host_template:
name: HW-Alcatel-OmniSwitch-custom
alias: Materiel Alcatel OmniSwitch
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Alcatel-OmniSwitch
alias: Switch Alcatel OmniSwitch (SNMP)
notification:
perimetre: Switch Alcatel OmniSwitch (SNMP)
calendrier:
name: TP-HW-Alcatel-OmniSwitch-24x7
modele: 24x7
alias: Switch Alcatel OmniSwitch (SNMP), en permanence
groupe: CG-HW-Alcatel-OmniSwitch
criticite: Critique
impact: "Coupure reseau sur le perimetre desservi"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU de l'equipement
line: "$CENTREONPLUGINS$/centreon_alcatel_omniswitch_snmp.pl --plugin=network::alcatel::omniswitch::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_alcatel_omniswitch_snmp.pl --plugin=network::alcatel::omniswitch::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Hardware
alias: Hardware
description: Alimentations, ventilateurs et sondes de temperature
line: "$CENTREONPLUGINS$/centreon_alcatel_omniswitch_snmp.pl --plugin=network::alcatel::omniswitch::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat, trafic et erreurs des interfaces
line: "$CENTREONPLUGINS$/centreon_alcatel_omniswitch_snmp.pl --plugin=network::alcatel::omniswitch::snmp::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic --add-errors --warning-in-traffic='$_SERVICEWARNINGIN$' --critical-in-traffic='$_SERVICECRITICALIN$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: WARNINGIN, value: "80", description: "Seuil warning trafic entrant (%)"}
- {name: CRITICALIN, value: "90", description: "Seuil critical trafic entrant (%)"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
- name: Uptime
alias: Uptime
description: Duree depuis le dernier redemarrage
default: false
line: "$CENTREONPLUGINS$/centreon_alcatel_omniswitch_snmp.pl --plugin=network::alcatel::omniswitch::snmp::plugin --mode=uptime --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-uptime='$_SERVICEWARNING$' --critical-uptime='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning (secondes)"}
- {name: CRITICAL, value: "@0:600", description: "Seuil critical (secondes)"}
- {name: EXTRAOPTIONS, value: "--unit=s", description: "Options supplementaires"}
+52
View File
@@ -0,0 +1,52 @@
id: hw-aruba-instant-snmp
name: Bornes wifi Aruba Instant (SNMP)
category: network
status: to-verify
plugin: centreon_aruba_instant_snmp.pl
description: Supervision d'un cluster de bornes wifi Aruba Instant en SNMP (bornes, clients, radios).
host_template:
name: HW-Aruba-Instant-custom
alias: Materiel Aruba Instant
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Aruba-Instant
alias: Bornes wifi Aruba Instant (SNMP)
notification:
perimetre: Bornes wifi Aruba Instant
calendrier:
name: TP-HW-Aruba-Instant-24x7
modele: 24x7
alias: Bornes wifi Aruba Instant (SNMP), en permanence
groupe: CG-HW-Aruba-Instant
criticite: Majeure
impact: "Couverture wifi degradee ou absente sur le site"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Ap-Status
alias: Ap-Status
description: Etat des bornes du cluster
line: "$CENTREONPLUGINS$/centreon_aruba_instant_snmp.pl --plugin=network::aruba::instant::snmp::plugin --mode=ap-status --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --filter-name='$_SERVICEFILTERNAME$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: FILTERNAME, value: "", description: "Filtre sur le nom de la borne"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Clients
alias: Clients
description: Nombre de clients associes
line: "$CENTREONPLUGINS$/centreon_aruba_instant_snmp.pl --plugin=network::aruba::instant::snmp::plugin --mode=clients --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning='$_SERVICEWARNING$' --critical='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning sur le nombre de clients"}
- {name: CRITICAL, value: "", description: "Seuil critical sur le nombre de clients"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Radios
alias: Radios
description: Etat et charge des radios
default: false
line: "$CENTREONPLUGINS$/centreon_aruba_instant_snmp.pl --plugin=network::aruba::instant::snmp::plugin --mode=radios --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+71
View File
@@ -0,0 +1,71 @@
id: hw-aruba-snmp
name: Switch Aruba (SNMP)
category: network
status: to-verify
plugin: centreon_aruba_snmp.pl
description: Supervision d'un commutateur Aruba en SNMP (CPU, memoire, materiel, interfaces).
host_template:
name: HW-Aruba-SNMP-custom
alias: Materiel Aruba SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Aruba-SNMP
alias: Switch Aruba (SNMP)
notification:
perimetre: Switch Aruba (SNMP)
calendrier:
name: TP-HW-Aruba-SNMP-24x7
modele: 24x7
alias: Switch Aruba (SNMP), en permanence
groupe: CG-HW-Aruba-SNMP
criticite: Critique
impact: "Coupure reseau sur le perimetre desservi"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU de l'equipement
line: "$CENTREONPLUGINS$/centreon_aruba_snmp.pl --plugin=network::aruba::standard::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_aruba_snmp.pl --plugin=network::aruba::standard::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Hardware
alias: Hardware
description: Alimentations, ventilateurs et sondes de temperature
line: "$CENTREONPLUGINS$/centreon_aruba_snmp.pl --plugin=network::aruba::standard::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat, trafic et erreurs des interfaces
line: "$CENTREONPLUGINS$/centreon_aruba_snmp.pl --plugin=network::aruba::standard::snmp::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic --add-errors --warning-in-traffic='$_SERVICEWARNINGIN$' --critical-in-traffic='$_SERVICECRITICALIN$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: WARNINGIN, value: "80", description: "Seuil warning trafic entrant (%)"}
- {name: CRITICALIN, value: "90", description: "Seuil critical trafic entrant (%)"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
- name: Uptime
alias: Uptime
description: Duree depuis le dernier redemarrage
default: false
line: "$CENTREONPLUGINS$/centreon_aruba_snmp.pl --plugin=network::aruba::standard::snmp::plugin --mode=uptime --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-uptime='$_SERVICEWARNING$' --critical-uptime='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning (secondes)"}
- {name: CRITICAL, value: "@0:600", description: "Seuil critical (secondes)"}
- {name: EXTRAOPTIONS, value: "--unit=s", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: hw-cisco-snmp
name: Switch / routeur Cisco (SNMP)
category: hardware
category: network
status: verified
plugin: centreon_cisco_standard_snmp.pl
description: Supervision d'un equipement Cisco IOS / IOS-XE en SNMP (CPU, memoire, environnement materiel, interfaces).
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Cisco-SNMP
alias: Switch / routeur Cisco (SNMP)
notification:
perimetre: Switch / routeur Cisco (SNMP)
calendrier:
name: TP-HW-Cisco-SNMP-24x7
modele: 24x7
alias: Switch / routeur Cisco (SNMP), en permanence
groupe: CG-HW-Cisco-SNMP
criticite: Critique
impact: "Coupure reseau sur le perimetre desservi"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
+62
View File
@@ -0,0 +1,62 @@
id: hw-cisco-wlc-snmp
name: Controleur wifi Cisco WLC (SNMP)
category: network
status: to-verify
plugin: centreon_cisco_wlc_snmp.pl
description: Supervision d'un controleur wifi Cisco WLC en SNMP (bornes rattachees, clients, CPU, memoire).
host_template:
name: HW-Cisco-WLC-custom
alias: Materiel Cisco WLC
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Cisco-WLC
alias: Controleur wifi Cisco WLC (SNMP)
notification:
perimetre: Controleur wifi Cisco WLC
calendrier:
name: TP-HW-Cisco-WLC-24x7
modele: 24x7
alias: Controleur wifi Cisco WLC (SNMP), en permanence
groupe: CG-HW-Cisco-WLC
criticite: Majeure
impact: "Couverture wifi degradee ou absente sur le site"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Ap-Status
alias: Ap-Status
description: Etat des bornes rattachees au controleur
line: "$CENTREONPLUGINS$/centreon_cisco_wlc_snmp.pl --plugin=network::cisco::wlc::snmp::plugin --mode=ap-status --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --filter-name='$_SERVICEFILTERNAME$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: FILTERNAME, value: "", description: "Filtre sur le nom de la borne"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Ap-Usage
alias: Ap-Usage
description: Clients connectes et charge des bornes
line: "$CENTREONPLUGINS$/centreon_cisco_wlc_snmp.pl --plugin=network::cisco::wlc::snmp::plugin --mode=ap-usage --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --filter-name='$_SERVICEFILTERNAME$' --warning-clients='$_SERVICEWARNING$' --critical-clients='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: FILTERNAME, value: "", description: "Filtre sur le nom de la borne"}
- {name: WARNING, value: "", description: "Seuil warning sur le nombre de clients"}
- {name: CRITICAL, value: "", description: "Seuil critical sur le nombre de clients"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Cpu
alias: Cpu
description: Charge CPU du controleur
line: "$CENTREONPLUGINS$/centreon_cisco_wlc_snmp.pl --plugin=network::cisco::wlc::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation memoire du controleur
line: "$CENTREONPLUGINS$/centreon_cisco_wlc_snmp.pl --plugin=network::cisco::wlc::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -0,0 +1,71 @@
id: hw-dell-powerconnect-snmp
name: Switch Dell PowerConnect et N-Series (SNMP)
category: network
status: to-verify
plugin: centreon_dell_powerconnect_snmp.pl
description: Supervision d'un commutateur Dell PowerConnect ou N-Series en SNMP.
host_template:
name: HW-Dell-PowerConnect-custom
alias: Materiel Dell PowerConnect
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Dell-PowerConnect
alias: Switch Dell PowerConnect et N-Series (SNMP)
notification:
perimetre: Switch Dell PowerConnect et N-Series (SNMP)
calendrier:
name: TP-HW-Dell-PowerConnect-24x7
modele: 24x7
alias: Switch Dell PowerConnect et N-Series (SNMP), en permanence
groupe: CG-HW-Dell-PowerConnect
criticite: Critique
impact: "Coupure reseau sur le perimetre desservi"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU de l'equipement
line: "$CENTREONPLUGINS$/centreon_dell_powerconnect_snmp.pl --plugin=network::dell::powerconnect::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_dell_powerconnect_snmp.pl --plugin=network::dell::powerconnect::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Hardware
alias: Hardware
description: Alimentations, ventilateurs et sondes de temperature
line: "$CENTREONPLUGINS$/centreon_dell_powerconnect_snmp.pl --plugin=network::dell::powerconnect::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat, trafic et erreurs des interfaces
line: "$CENTREONPLUGINS$/centreon_dell_powerconnect_snmp.pl --plugin=network::dell::powerconnect::snmp::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic --add-errors --warning-in-traffic='$_SERVICEWARNINGIN$' --critical-in-traffic='$_SERVICECRITICALIN$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: WARNINGIN, value: "80", description: "Seuil warning trafic entrant (%)"}
- {name: CRITICALIN, value: "90", description: "Seuil critical trafic entrant (%)"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
- name: Uptime
alias: Uptime
description: Duree depuis le dernier redemarrage
default: false
line: "$CENTREONPLUGINS$/centreon_dell_powerconnect_snmp.pl --plugin=network::dell::powerconnect::snmp::plugin --mode=uptime --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-uptime='$_SERVICEWARNING$' --critical-uptime='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning (secondes)"}
- {name: CRITICAL, value: "@0:600", description: "Seuil critical (secondes)"}
- {name: EXTRAOPTIONS, value: "--unit=s", description: "Options supplementaires"}
+71
View File
@@ -0,0 +1,71 @@
id: hw-extreme-snmp
name: Switch Extreme Networks (SNMP)
category: network
status: to-verify
plugin: centreon_extreme_snmp.pl
description: Supervision d'un commutateur Extreme Networks en SNMP.
host_template:
name: HW-Extreme-SNMP-custom
alias: Materiel Extreme SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Extreme-SNMP
alias: Switch Extreme Networks (SNMP)
notification:
perimetre: Switch Extreme Networks (SNMP)
calendrier:
name: TP-HW-Extreme-SNMP-24x7
modele: 24x7
alias: Switch Extreme Networks (SNMP), en permanence
groupe: CG-HW-Extreme-SNMP
criticite: Critique
impact: "Coupure reseau sur le perimetre desservi"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU de l'equipement
line: "$CENTREONPLUGINS$/centreon_extreme_snmp.pl --plugin=network::extreme::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_extreme_snmp.pl --plugin=network::extreme::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Hardware
alias: Hardware
description: Alimentations, ventilateurs et sondes de temperature
line: "$CENTREONPLUGINS$/centreon_extreme_snmp.pl --plugin=network::extreme::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat, trafic et erreurs des interfaces
line: "$CENTREONPLUGINS$/centreon_extreme_snmp.pl --plugin=network::extreme::snmp::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic --add-errors --warning-in-traffic='$_SERVICEWARNINGIN$' --critical-in-traffic='$_SERVICECRITICALIN$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: WARNINGIN, value: "80", description: "Seuil warning trafic entrant (%)"}
- {name: CRITICALIN, value: "90", description: "Seuil critical trafic entrant (%)"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
- name: Uptime
alias: Uptime
description: Duree depuis le dernier redemarrage
default: false
line: "$CENTREONPLUGINS$/centreon_extreme_snmp.pl --plugin=network::extreme::snmp::plugin --mode=uptime --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-uptime='$_SERVICEWARNING$' --critical-uptime='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning (secondes)"}
- {name: CRITICAL, value: "@0:600", description: "Seuil critical (secondes)"}
- {name: EXTRAOPTIONS, value: "--unit=s", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: hw-fortinet-fortigate-snmp
name: Firewall Fortinet FortiGate (SNMP)
category: hardware
category: network
status: verified
plugin: centreon_fortinet_fortigate.pl
description: Supervision d'un FortiGate en SNMP (CPU, memoire, disque, sessions, tunnels VPN, cluster HA, interfaces).
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Fortinet-FortiGate-SNMP
alias: Firewall Fortinet FortiGate (SNMP)
notification:
perimetre: Firewall Fortinet FortiGate (SNMP)
calendrier:
name: TP-HW-Fortinet-FortiGate-SNMP-24x7
modele: 24x7
alias: Firewall Fortinet FortiGate (SNMP), en permanence
groupe: CG-HW-Fortinet-FortiGate-SNMP
criticite: Critique
impact: "Pare-feu en defaut, acces reseau compromis"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
+71
View File
@@ -0,0 +1,71 @@
id: hw-hp-procurve-snmp
name: Switch HP ProCurve et Aruba (SNMP)
category: network
status: to-verify
plugin: centreon_hp_procurve_snmp.pl
description: Supervision d'un commutateur HP ProCurve ou Aruba en SNMP.
host_template:
name: HW-HP-Procurve-SNMP-custom
alias: Materiel HP ProCurve SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-HP-Procurve-SNMP
alias: Switch HP ProCurve et Aruba (SNMP)
notification:
perimetre: Switch HP ProCurve et Aruba (SNMP)
calendrier:
name: TP-HW-HP-Procurve-SNMP-24x7
modele: 24x7
alias: Switch HP ProCurve et Aruba (SNMP), en permanence
groupe: CG-HW-HP-Procurve-SNMP
criticite: Critique
impact: "Coupure reseau sur le perimetre desservi"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU de l'equipement
line: "$CENTREONPLUGINS$/centreon_hp_procurve_snmp.pl --plugin=network::hp::procurve::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_hp_procurve_snmp.pl --plugin=network::hp::procurve::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Hardware
alias: Hardware
description: Etat des composants materiels
line: "$CENTREONPLUGINS$/centreon_hp_procurve_snmp.pl --plugin=network::hp::procurve::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat et trafic des interfaces
line: "$CENTREONPLUGINS$/centreon_hp_procurve_snmp.pl --plugin=network::hp::procurve::snmp::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic --warning-in-traffic='$_SERVICEWARNINGIN$' --critical-in-traffic='$_SERVICECRITICALIN$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: WARNINGIN, value: "80", description: "Seuil warning trafic entrant (%)"}
- {name: CRITICALIN, value: "90", description: "Seuil critical trafic entrant (%)"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
- name: Uptime
alias: Uptime
description: Duree depuis le dernier redemarrage
default: false
line: "$CENTREONPLUGINS$/centreon_hp_procurve_snmp.pl --plugin=network::hp::procurve::snmp::plugin --mode=uptime --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-uptime='$_SERVICEWARNING$' --critical-uptime='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning (secondes)"}
- {name: CRITICAL, value: "@0:600", description: "Seuil critical (secondes)"}
- {name: EXTRAOPTIONS, value: "--unit=s", description: "Options supplementaires"}
+71
View File
@@ -0,0 +1,71 @@
id: hw-huawei-snmp
name: Switch et routeur Huawei (SNMP)
category: network
status: to-verify
plugin: centreon_huawei_snmp.pl
description: Supervision d'un equipement reseau Huawei en SNMP.
host_template:
name: HW-Huawei-SNMP-custom
alias: Materiel Huawei SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Huawei-SNMP
alias: Switch et routeur Huawei (SNMP)
notification:
perimetre: Switch et routeur Huawei (SNMP)
calendrier:
name: TP-HW-Huawei-SNMP-24x7
modele: 24x7
alias: Switch et routeur Huawei (SNMP), en permanence
groupe: CG-HW-Huawei-SNMP
criticite: Critique
impact: "Coupure reseau sur le perimetre desservi"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU de l'equipement
line: "$CENTREONPLUGINS$/centreon_huawei_snmp.pl --plugin=network::huawei::standard::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_huawei_snmp.pl --plugin=network::huawei::standard::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Hardware
alias: Hardware
description: Alimentations, ventilateurs et sondes de temperature
line: "$CENTREONPLUGINS$/centreon_huawei_snmp.pl --plugin=network::huawei::standard::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat, trafic et erreurs des interfaces
line: "$CENTREONPLUGINS$/centreon_huawei_snmp.pl --plugin=network::huawei::standard::snmp::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic --add-errors --warning-in-traffic='$_SERVICEWARNINGIN$' --critical-in-traffic='$_SERVICECRITICALIN$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: WARNINGIN, value: "80", description: "Seuil warning trafic entrant (%)"}
- {name: CRITICALIN, value: "90", description: "Seuil critical trafic entrant (%)"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
- name: Uptime
alias: Uptime
description: Duree depuis le dernier redemarrage
default: false
line: "$CENTREONPLUGINS$/centreon_huawei_snmp.pl --plugin=network::huawei::standard::snmp::plugin --mode=uptime --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-uptime='$_SERVICEWARNING$' --critical-uptime='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning (secondes)"}
- {name: CRITICAL, value: "@0:600", description: "Seuil critical (secondes)"}
- {name: EXTRAOPTIONS, value: "--unit=s", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: hw-juniper-junos-snmp
name: Juniper JunOS (SNMP)
category: hardware
category: network
status: to-verify
plugin: centreon_juniper_junos_snmp.pl
description: Supervision d'un equipement Juniper sous JunOS en SNMP. Verifier le nom du script (centreon_juniper_junos_snmp.pl) sur l'installation cible.
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Juniper-JunOS-SNMP
alias: Juniper JunOS (SNMP)
notification:
perimetre: Juniper JunOS (SNMP)
calendrier:
name: TP-HW-Juniper-JunOS-SNMP-24x7
modele: 24x7
alias: Juniper JunOS (SNMP), en permanence
groupe: CG-HW-Juniper-JunOS-SNMP
criticite: Critique
impact: "Coupure reseau sur le perimetre desservi"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
+71
View File
@@ -0,0 +1,71 @@
id: hw-mikrotik-snmp
name: MikroTik RouterOS (SNMP)
category: network
status: to-verify
plugin: centreon_mikrotik_snmp.pl
description: Supervision d'un equipement MikroTik sous RouterOS en SNMP.
host_template:
name: HW-MikroTik-SNMP-custom
alias: Materiel MikroTik SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-MikroTik-SNMP
alias: MikroTik RouterOS (SNMP)
notification:
perimetre: MikroTik RouterOS (SNMP)
calendrier:
name: TP-HW-MikroTik-SNMP-24x7
modele: 24x7
alias: MikroTik RouterOS (SNMP), en permanence
groupe: CG-HW-MikroTik-SNMP
criticite: Majeure
impact: "Coupure reseau sur le perimetre desservi"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU de l'equipement
line: "$CENTREONPLUGINS$/centreon_mikrotik_snmp.pl --plugin=network::mikrotik::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_mikrotik_snmp.pl --plugin=network::mikrotik::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Hardware
alias: Hardware
description: Etat des composants materiels
line: "$CENTREONPLUGINS$/centreon_mikrotik_snmp.pl --plugin=network::mikrotik::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat et trafic des interfaces
line: "$CENTREONPLUGINS$/centreon_mikrotik_snmp.pl --plugin=network::mikrotik::snmp::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic --warning-in-traffic='$_SERVICEWARNINGIN$' --critical-in-traffic='$_SERVICECRITICALIN$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: WARNINGIN, value: "80", description: "Seuil warning trafic entrant (%)"}
- {name: CRITICALIN, value: "90", description: "Seuil critical trafic entrant (%)"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
- name: Uptime
alias: Uptime
description: Duree depuis le dernier redemarrage
default: false
line: "$CENTREONPLUGINS$/centreon_mikrotik_snmp.pl --plugin=network::mikrotik::snmp::plugin --mode=uptime --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-uptime='$_SERVICEWARNING$' --critical-uptime='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning (secondes)"}
- {name: CRITICAL, value: "@0:600", description: "Seuil critical (secondes)"}
- {name: EXTRAOPTIONS, value: "--unit=s", description: "Options supplementaires"}
+71
View File
@@ -0,0 +1,71 @@
id: hw-paloalto-snmp
name: Pare-feu Palo Alto (SNMP)
category: network
status: to-verify
plugin: centreon_paloalto_snmp.pl
description: Supervision d'un pare-feu Palo Alto en SNMP.
host_template:
name: HW-PaloAlto-SNMP-custom
alias: Materiel Palo Alto SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-PaloAlto-SNMP
alias: Pare-feu Palo Alto (SNMP)
notification:
perimetre: Pare-feu Palo Alto (SNMP)
calendrier:
name: TP-HW-PaloAlto-SNMP-24x7
modele: 24x7
alias: Pare-feu Palo Alto (SNMP), en permanence
groupe: CG-HW-PaloAlto-SNMP
criticite: Critique
impact: "Pare-feu en defaut, acces reseau compromis"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU de l'equipement
line: "$CENTREONPLUGINS$/centreon_paloalto_snmp.pl --plugin=network::paloalto::standard::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_paloalto_snmp.pl --plugin=network::paloalto::standard::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Hardware
alias: Hardware
description: Etat des composants materiels
line: "$CENTREONPLUGINS$/centreon_paloalto_snmp.pl --plugin=network::paloalto::standard::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat et trafic des interfaces
line: "$CENTREONPLUGINS$/centreon_paloalto_snmp.pl --plugin=network::paloalto::standard::snmp::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic --warning-in-traffic='$_SERVICEWARNINGIN$' --critical-in-traffic='$_SERVICECRITICALIN$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: WARNINGIN, value: "80", description: "Seuil warning trafic entrant (%)"}
- {name: CRITICALIN, value: "90", description: "Seuil critical trafic entrant (%)"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
- name: Uptime
alias: Uptime
description: Duree depuis le dernier redemarrage
default: false
line: "$CENTREONPLUGINS$/centreon_paloalto_snmp.pl --plugin=network::paloalto::standard::snmp::plugin --mode=uptime --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-uptime='$_SERVICEWARNING$' --critical-uptime='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning (secondes)"}
- {name: CRITICAL, value: "@0:600", description: "Seuil critical (secondes)"}
- {name: EXTRAOPTIONS, value: "--unit=s", description: "Options supplementaires"}
+64
View File
@@ -0,0 +1,64 @@
id: hw-pfsense-snmp
name: Pare-feu pfSense (SNMP)
category: network
status: to-verify
plugin: centreon_pfsense_snmp.pl
description: Supervision d'un pare-feu pfSense en SNMP (CPU, memoire, etat des regles, interfaces).
prerequis:
notes: |
Activer le service SNMP dans Services > SNMP, et cocher les modules Host Resources
et UCD si la supervision systeme est souhaitee.
host_template:
name: HW-pfSense-SNMP-custom
alias: Materiel pfSense SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-pfSense-SNMP
alias: Pare-feu pfSense (SNMP)
notification:
perimetre: Pare-feu pfSense (SNMP)
calendrier:
name: TP-HW-pfSense-SNMP-24x7
modele: 24x7
alias: Pare-feu pfSense (SNMP), en permanence
groupe: CG-HW-pfSense-SNMP
criticite: Critique
impact: "Pare-feu en defaut, acces reseau compromis"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU du boitier
line: "$CENTREONPLUGINS$/centreon_pfsense_snmp.pl --plugin=apps::pfsense::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_pfsense_snmp.pl --plugin=apps::pfsense::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Rules-Drop
alias: Rules-Drop
description: Paquets rejetes par les regles de filtrage
default: false
line: "$CENTREONPLUGINS$/centreon_pfsense_snmp.pl --plugin=apps::pfsense::snmp::plugin --mode=rules-drop --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat et trafic des interfaces
line: "$CENTREONPLUGINS$/centreon_generic_snmp.pl --plugin=snmp_standard::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
@@ -0,0 +1,44 @@
id: hw-ruckus-zonedirector-snmp
name: Controleur wifi Ruckus ZoneDirector (SNMP)
category: network
status: to-verify
plugin: centreon_ruckus_zonedirector_snmp.pl
description: Supervision d'un controleur wifi Ruckus ZoneDirector en SNMP (bornes, clients, systeme).
host_template:
name: HW-Ruckus-ZoneDirector-custom
alias: Materiel Ruckus ZoneDirector
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Ruckus-ZoneDirector
alias: Controleur wifi Ruckus ZoneDirector (SNMP)
notification:
perimetre: Controleur wifi Ruckus
calendrier:
name: TP-HW-Ruckus-ZoneDirector-24x7
modele: 24x7
alias: Controleur wifi Ruckus ZoneDirector (SNMP), en permanence
groupe: CG-HW-Ruckus-ZoneDirector
criticite: Majeure
impact: "Couverture wifi degradee ou absente sur le site"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Ap-Status
alias: Ap-Status
description: Etat des bornes rattachees
line: "$CENTREONPLUGINS$/centreon_ruckus_zonedirector_snmp.pl --plugin=network::ruckus::zonedirector::snmp::plugin --mode=ap-status --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: System
alias: System
description: CPU, memoire et etat general du controleur
line: "$CENTREONPLUGINS$/centreon_ruckus_zonedirector_snmp.pl --plugin=network::ruckus::zonedirector::snmp::plugin --mode=system --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-cpu='$_SERVICEWARNING$' --critical-cpu='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning CPU en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical CPU en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+71
View File
@@ -0,0 +1,71 @@
id: hw-stormshield-snmp
name: Pare-feu Stormshield (SNMP)
category: network
status: to-verify
plugin: centreon_stormshield_snmp.pl
description: Supervision d'un pare-feu Stormshield SNS en SNMP.
host_template:
name: HW-Stormshield-SNMP-custom
alias: Materiel Stormshield SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Stormshield-SNMP
alias: Pare-feu Stormshield (SNMP)
notification:
perimetre: Pare-feu Stormshield (SNMP)
calendrier:
name: TP-HW-Stormshield-SNMP-24x7
modele: 24x7
alias: Pare-feu Stormshield (SNMP), en permanence
groupe: CG-HW-Stormshield-SNMP
criticite: Critique
impact: "Pare-feu en defaut, acces reseau compromis"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU de l'equipement
line: "$CENTREONPLUGINS$/centreon_stormshield_snmp.pl --plugin=network::stormshield::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_stormshield_snmp.pl --plugin=network::stormshield::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Hardware
alias: Hardware
description: Etat des composants materiels
line: "$CENTREONPLUGINS$/centreon_stormshield_snmp.pl --plugin=network::stormshield::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat et trafic des interfaces
line: "$CENTREONPLUGINS$/centreon_stormshield_snmp.pl --plugin=network::stormshield::snmp::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic --warning-in-traffic='$_SERVICEWARNINGIN$' --critical-in-traffic='$_SERVICECRITICALIN$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: WARNINGIN, value: "80", description: "Seuil warning trafic entrant (%)"}
- {name: CRITICALIN, value: "90", description: "Seuil critical trafic entrant (%)"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
- name: Uptime
alias: Uptime
description: Duree depuis le dernier redemarrage
default: false
line: "$CENTREONPLUGINS$/centreon_stormshield_snmp.pl --plugin=network::stormshield::snmp::plugin --mode=uptime --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-uptime='$_SERVICEWARNING$' --critical-uptime='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning (secondes)"}
- {name: CRITICAL, value: "@0:600", description: "Seuil critical (secondes)"}
- {name: EXTRAOPTIONS, value: "--unit=s", description: "Options supplementaires"}
+71
View File
@@ -0,0 +1,71 @@
id: hw-ubiquiti-snmp
name: Ubiquiti UniFi et EdgeMax (SNMP)
category: network
status: to-verify
plugin: centreon_ubnt_snmp.pl
description: Supervision d'un equipement Ubiquiti en SNMP.
host_template:
name: HW-Ubiquiti-SNMP-custom
alias: Materiel Ubiquiti SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Ubiquiti-SNMP
alias: Ubiquiti UniFi et EdgeMax (SNMP)
notification:
perimetre: Ubiquiti UniFi et EdgeMax (SNMP)
calendrier:
name: TP-HW-Ubiquiti-SNMP-24x7
modele: 24x7
alias: Ubiquiti UniFi et EdgeMax (SNMP), en permanence
groupe: CG-HW-Ubiquiti-SNMP
criticite: Majeure
impact: "Coupure reseau ou wifi sur le perimetre desservi"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
description: Charge CPU de l'equipement
line: "$CENTREONPLUGINS$/centreon_ubnt_snmp.pl --plugin=network::ubnt::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Memory
alias: Memory
description: Utilisation de la memoire
line: "$CENTREONPLUGINS$/centreon_ubnt_snmp.pl --plugin=network::ubnt::snmp::plugin --mode=memory --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Hardware
alias: Hardware
description: Etat des composants materiels
line: "$CENTREONPLUGINS$/centreon_ubnt_snmp.pl --plugin=network::ubnt::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Interfaces
alias: Interfaces
description: Etat et trafic des interfaces
line: "$CENTREONPLUGINS$/centreon_ubnt_snmp.pl --plugin=network::ubnt::snmp::plugin --mode=interfaces --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --interface='$_SERVICEINTERFACE$' --add-status --add-traffic --warning-in-traffic='$_SERVICEWARNINGIN$' --critical-in-traffic='$_SERVICECRITICALIN$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: INTERFACE, value: "", description: "Filtre sur le nom de l'interface"}
- {name: WARNINGIN, value: "80", description: "Seuil warning trafic entrant (%)"}
- {name: CRITICALIN, value: "90", description: "Seuil critical trafic entrant (%)"}
- {name: EXTRAOPTIONS, value: "--interface-use-adminstatus --name", description: "Options supplementaires"}
- name: Uptime
alias: Uptime
description: Duree depuis le dernier redemarrage
default: false
line: "$CENTREONPLUGINS$/centreon_ubnt_snmp.pl --plugin=network::ubnt::snmp::plugin --mode=uptime --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-uptime='$_SERVICEWARNING$' --critical-uptime='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning (secondes)"}
- {name: CRITICAL, value: "@0:600", description: "Seuil critical (secondes)"}
- {name: EXTRAOPTIONS, value: "--unit=s", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: os-aix-snmp
name: AIX (SNMP)
category: system
category: operating-system
status: to-verify
plugin: centreon_aix_snmp.pl
description: Supervision d'un serveur AIX via SNMP. Verifier le nom exact du plugin sur la version de centreon-plugins installee.
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-OS-AIX-SNMP
alias: AIX (SNMP)
notification:
perimetre: AIX (SNMP)
calendrier:
name: TP-OS-AIX-SNMP-24x7
modele: 24x7
alias: AIX (SNMP), en permanence
groupe: CG-OS-AIX-SNMP
criticite: Majeure
impact: "Serveur indisponible ou degrade"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
@@ -1,6 +1,6 @@
id: os-freebsd-snmp
name: FreeBSD (SNMP)
category: system
category: operating-system
status: to-verify
plugin: centreon_freebsd_snmp.pl
description: Supervision d'un serveur FreeBSD via SNMP. Verifier le nom exact du plugin sur la version de centreon-plugins installee.
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-OS-FreeBSD-SNMP
alias: FreeBSD (SNMP)
notification:
perimetre: FreeBSD (SNMP)
calendrier:
name: TP-OS-FreeBSD-SNMP-24x7
modele: 24x7
alias: FreeBSD (SNMP), en permanence
groupe: CG-OS-FreeBSD-SNMP
criticite: Majeure
impact: "Serveur indisponible ou degrade"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
@@ -1,6 +1,6 @@
id: os-linux-nrpe
name: Linux (NRPE)
category: system
category: operating-system
status: verified
plugin: check_centreon_nrpe
description: Supervision Linux par agent NRPE (commandes definies cote client dans nrpe.cfg).
@@ -12,6 +12,28 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: NRPEPORT, value: "5666", description: "Port d'ecoute de l'agent NRPE"}
prerequis:
paquets:
debian: [centreon-nrpe3-plugin]
rhel: [centreon-nrpe3-plugin]
notes: |
Cote client supervise : installer l'agent NRPE, declarer l'adresse du
collecteur dans allowed_hosts, et definir les commandes appelees.
groupe_hote:
name: HG-OS-Linux-NRPE
alias: Linux (NRPE)
notification:
perimetre: Linux (NRPE)
calendrier:
name: TP-OS-Linux-NRPE-24x7
modele: 24x7
alias: Linux (NRPE), en permanence
groupe: CG-OS-Linux-NRPE
criticite: Majeure
impact: "Serveur indisponible ou degrade"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
@@ -1,6 +1,6 @@
id: os-linux-snmp
name: Linux (SNMP)
category: system
category: operating-system
status: verified
plugin: centreon_linux_snmp.pl
description: Supervision d'un serveur Linux via SNMP avec centreon-plugins (CPU, memoire, swap, systemes de fichiers, charge, interfaces, uptime).
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-OS-Linux-SNMP
alias: Linux (SNMP)
notification:
perimetre: Linux (SNMP)
calendrier:
name: TP-OS-Linux-SNMP-24x7
modele: 24x7
alias: Linux (SNMP), en permanence
groupe: CG-OS-Linux-SNMP
criticite: Majeure
impact: "Serveur indisponible ou degrade"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
@@ -1,6 +1,6 @@
id: os-solaris-snmp
name: Solaris (SNMP)
category: system
category: operating-system
status: to-verify
plugin: centreon_solaris_snmp.pl
description: Supervision d'un serveur Solaris via SNMP. Verifier le nom exact du plugin sur la version de centreon-plugins installee.
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-OS-Solaris-SNMP
alias: Solaris (SNMP)
notification:
perimetre: Solaris (SNMP)
calendrier:
name: TP-OS-Solaris-SNMP-24x7
modele: 24x7
alias: Solaris (SNMP), en permanence
groupe: CG-OS-Solaris-SNMP
criticite: Majeure
impact: "Serveur indisponible ou degrade"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
@@ -1,6 +1,6 @@
id: os-windows-nsclient
name: Windows (NSClient++ / check_nt)
category: system
category: operating-system
status: verified
plugin: check_nt
description: Supervision Windows par l'agent NSClient++ en protocole NSC (check_nt), utile quand SNMP n'est pas ouvert.
@@ -13,6 +13,21 @@ host_template:
macros:
- {name: NSCLIENTPORT, value: "12489", description: "Port d'ecoute NSClient++"}
- {name: NSCLIENTPASSWORD, value: "", description: "Mot de passe NSClient++", is_password: true}
groupe_hote:
name: HG-OS-Windows-NSClient
alias: Windows (NSClient++ / check_nt)
notification:
perimetre: Windows (NSClient++ / check_nt)
calendrier:
name: TP-OS-Windows-NSClient-24x7
modele: 24x7
alias: Windows (NSClient++ / check_nt), en permanence
groupe: CG-OS-Windows-NSClient
criticite: Majeure
impact: "Serveur indisponible ou degrade"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
@@ -1,6 +1,6 @@
id: os-windows-snmp
name: Windows (SNMP)
category: system
category: operating-system
status: verified
plugin: centreon_windows_snmp.pl
description: Supervision d'un serveur Windows via SNMP (CPU, memoire, disques, services, interfaces, uptime).
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-OS-Windows-SNMP
alias: Windows (SNMP)
notification:
perimetre: Windows (SNMP)
calendrier:
name: TP-OS-Windows-SNMP-24x7
modele: 24x7
alias: Windows (SNMP), en permanence
groupe: CG-OS-Windows-SNMP
criticite: Majeure
impact: "Serveur indisponible ou degrade"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
@@ -1,6 +1,6 @@
id: hw-printer-rfc3805
name: Imprimante reseau (RFC 3805)
category: hardware
category: printer
status: to-verify
plugin: centreon_printer_standard_rfc3805.pl
description: Supervision d'une imprimante compatible RFC 3805 (niveaux de consommables, bacs papier, etat general). Verifier les modes disponibles.
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Printer-RFC3805
alias: Imprimante reseau (RFC 3805)
notification:
perimetre: Imprimante reseau (RFC 3805)
calendrier:
name: TP-HW-Printer-RFC3805-Heures-Ouvrees
modele: Heures-Ouvrees
alias: Imprimante reseau (RFC 3805), heures ouvrees
groupe: CG-HW-Printer-RFC3805
criticite: Mineure
impact: "Impression indisponible ou consommable epuise"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Marker-Supply
alias: Marker-Supply
+59
View File
@@ -0,0 +1,59 @@
id: app-ldap
name: Annuaire LDAP
category: protocol
status: to-verify
plugin: centreon_ldap.pl
description: Supervision d'un annuaire LDAP ou Active Directory (temps de reponse d'une recherche, disponibilite).
prerequis:
paquets:
debian: [libnet-ldap-perl]
rhel: [perl-LDAP]
notes: |
Un compte de lecture seule suffit. Preferer une recherche portant sur une base
restreinte plutot que sur la racine de l'annuaire.
host_template:
name: App-LDAP-custom
alias: Applicatif LDAP
parents: [generic-active-host-custom]
macros:
- {name: LDAPPORT, value: "389", description: "Port d'ecoute"}
- {name: LDAPBINDDN, value: "", description: "Compte de connexion (DN complet)"}
- {name: LDAPBINDPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: LDAPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-LDAP
alias: Annuaire LDAP
notification:
perimetre: Annuaire LDAP
calendrier:
name: TP-App-LDAP-24x7
modele: 24x7
alias: Annuaire LDAP, en permanence
groupe: CG-App-LDAP
criticite: Critique
impact: "Authentification et annuaire indisponibles, la plupart des applications s'arretent"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Search
alias: Search
description: Temps de reponse d'une recherche
line: "$CENTREONPLUGINS$/centreon_ldap.pl --plugin=apps::protocols::ldap::plugin --mode=search --hostname=$HOSTADDRESS$ --port='$_HOSTLDAPPORT$' --bind-dn='$_HOSTLDAPBINDDN$' --bind-password='$_HOSTLDAPBINDPASSWORD$' --search-base='$_SERVICESEARCHBASE$' --search-filter='$_SERVICESEARCHFILTER$' --warning='$_SERVICEWARNING$' --critical='$_SERVICECRITICAL$' $_HOSTLDAPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: SEARCHBASE, value: "", description: "Base de recherche, ex. dc=exemple,dc=fr"}
- {name: SEARCHFILTER, value: "(objectClass=*)", description: "Filtre de recherche"}
- {name: WARNING, value: "1", description: "Temps de reponse warning (s)"}
- {name: CRITICAL, value: "3", description: "Temps de reponse critical (s)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Search-Count
alias: Search-Count
description: Nombre d'entrees retournees par une recherche
default: false
line: "$CENTREONPLUGINS$/centreon_ldap.pl --plugin=apps::protocols::ldap::plugin --mode=search --hostname=$HOSTADDRESS$ --port='$_HOSTLDAPPORT$' --bind-dn='$_HOSTLDAPBINDDN$' --bind-password='$_HOSTLDAPBINDPASSWORD$' --search-base='$_SERVICESEARCHBASE$' --search-filter='$_SERVICESEARCHFILTER$' --warning-entries='$_SERVICEWARNING$' --critical-entries='$_SERVICECRITICAL$' $_HOSTLDAPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: SEARCHBASE, value: "", description: "Base de recherche"}
- {name: SEARCHFILTER, value: "(objectClass=*)", description: "Filtre de recherche"}
- {name: WARNING, value: "", description: "Seuil warning sur le nombre d'entrees"}
- {name: CRITICAL, value: "1:", description: "Seuil critical sur le nombre d'entrees"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: app-protocols
name: Services reseau standards (HTTP, TCP, DNS, NTP, SSH)
category: application
category: protocol
status: verified
plugin: check_http
description: Sondes generiques basees sur les plugins Nagios livres avec Centreon. Utile pour tout service expose sans pack dedie.
@@ -9,6 +9,21 @@ host_template:
alias: Applicatif Protocoles reseau
parents: [generic-active-host-custom]
macros: []
groupe_hote:
name: HG-App-Protocols
alias: Services reseau standards (HTTP, TCP, DNS, NTP, SSH)
notification:
perimetre: Services reseau standards (HTTP, TCP, DNS, NTP, SSH)
calendrier:
name: TP-App-Protocols-24x7
modele: 24x7
alias: Services reseau standards (HTTP, TCP, DNS, NTP, SSH), en permanence
groupe: CG-App-Protocols
criticite: Majeure
impact: "Service reseau expose indisponible"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Http
alias: Http
@@ -1,6 +1,6 @@
id: os-generic-snmp
name: Equipement generique (SNMP standard)
category: system
category: protocol
status: verified
plugin: centreon_generic_snmp.pl
description: Supervision de tout equipement repondant aux MIB standard (HOST-RESOURCES, UCD, IF-MIB). Base de repli quand aucun pack constructeur ne correspond.
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-OS-Generic-SNMP
alias: Equipement generique (SNMP standard)
notification:
perimetre: Equipement generique (SNMP standard)
calendrier:
name: TP-OS-Generic-SNMP-24x7
modele: 24x7
alias: Equipement generique (SNMP standard), en permanence
groupe: CG-OS-Generic-SNMP
criticite: Majeure
impact: "Serveur indisponible ou degrade"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cpu
alias: Cpu
+57
View File
@@ -0,0 +1,57 @@
id: hw-emc-unity-restapi
name: Baie Dell EMC Unity (API REST)
category: storage
status: to-verify
plugin: centreon_emc_unity_restapi.pl
description: Supervision d'une baie Dell EMC Unity via son API REST (materiel, pools, disques, alertes).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
notes: |
Creer un compte de supervision avec le role Operator sur la baie.
host_template:
name: HW-EMC-Unity-custom
alias: Materiel Dell EMC Unity
parents: [generic-active-host-custom]
macros:
- {name: UNITYPORT, value: "443", description: "Port de l'API"}
- {name: UNITYUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: UNITYPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: UNITYEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-EMC-Unity
alias: Baie Dell EMC Unity (API REST)
notification:
perimetre: Baie Dell EMC Unity
calendrier:
name: TP-HW-EMC-Unity-24x7
modele: 24x7
alias: Baie Dell EMC Unity (API REST), en permanence
groupe: CG-HW-EMC-Unity
criticite: Critique
impact: "Stockage partage en defaut, machines et applications menacees"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Hardware
alias: Hardware
description: Etat des composants materiels de la baie
line: "$CENTREONPLUGINS$/centreon_emc_unity_restapi.pl --plugin=storage::emc::unity::restapi::plugin --mode=hardware --hostname=$HOSTADDRESS$ --port='$_HOSTUNITYPORT$' --api-username='$_HOSTUNITYUSERNAME$' --api-password='$_HOSTUNITYPASSWORD$' $_HOSTUNITYEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Pool-Usage
alias: Pool-Usage
description: Occupation des pools de stockage
line: "$CENTREONPLUGINS$/centreon_emc_unity_restapi.pl --plugin=storage::emc::unity::restapi::plugin --mode=pool-usage --hostname=$HOSTADDRESS$ --port='$_HOSTUNITYPORT$' --api-username='$_HOSTUNITYUSERNAME$' --api-password='$_HOSTUNITYPASSWORD$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTUNITYEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Alerts
alias: Alerts
description: Alertes remontees par la baie
line: "$CENTREONPLUGINS$/centreon_emc_unity_restapi.pl --plugin=storage::emc::unity::restapi::plugin --mode=alerts --hostname=$HOSTADDRESS$ --port='$_HOSTUNITYPORT$' --api-username='$_HOSTUNITYUSERNAME$' --api-password='$_HOSTUNITYPASSWORD$' $_HOSTUNITYEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+51
View File
@@ -0,0 +1,51 @@
id: hw-hp-msa-xmlapi
name: Baie HPE MSA et P2000 (API XML)
category: storage
status: to-verify
plugin: centreon_hp_p2000_xmlapi.pl
description: Supervision d'une baie HPE MSA ou P2000 via son API XML (materiel, volumes, disques).
prerequis:
paquets:
debian: [libwww-perl, libxml-libxml-perl]
rhel: [perl-libwww-perl, perl-XML-LibXML]
notes: |
Un compte de supervision en lecture seule suffit. Verifier le nom du plugin
selon le modele : les generations MSA recentes exposent une API differente.
host_template:
name: HW-HP-MSA-custom
alias: Materiel HPE MSA
parents: [generic-active-host-custom]
macros:
- {name: MSAUSERNAME, value: "monitor", description: "Compte de supervision"}
- {name: MSAPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: MSAEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-HP-MSA
alias: Baie HPE MSA et P2000 (API XML)
notification:
perimetre: Baie HPE MSA
calendrier:
name: TP-HW-HP-MSA-24x7
modele: 24x7
alias: Baie HPE MSA et P2000 (API XML), en permanence
groupe: CG-HW-HP-MSA
criticite: Critique
impact: "Stockage partage en defaut, machines et applications menacees"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Hardware
alias: Hardware
description: Etat des composants de la baie
line: "$CENTREONPLUGINS$/centreon_hp_p2000_xmlapi.pl --plugin=storage::hp::p2000::xmlapi::plugin --mode=hardware --hostname=$HOSTADDRESS$ --hp-username='$_HOSTMSAUSERNAME$' --hp-password='$_HOSTMSAPASSWORD$' $_HOSTMSAEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Volume-Usage
alias: Volume-Usage
description: Occupation des volumes
line: "$CENTREONPLUGINS$/centreon_hp_p2000_xmlapi.pl --plugin=storage::hp::p2000::xmlapi::plugin --mode=volume-usage --hostname=$HOSTADDRESS$ --hp-username='$_HOSTMSAUSERNAME$' --hp-password='$_HOSTMSAPASSWORD$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTMSAEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+50
View File
@@ -0,0 +1,50 @@
id: hw-ibm-storwize-ssh
name: Baie IBM Storwize et FlashSystem (SSH)
category: storage
status: to-verify
plugin: centreon_ibm_storwize_ssh.pl
description: Supervision d'une baie IBM Storwize ou FlashSystem par SSH (materiel, pools, evenements).
prerequis:
paquets:
debian: [libssh-perl, openssh-client]
rhel: [perl-Net-SSH-Perl, openssh-clients]
notes: |
Deposer la cle publique de l'utilisateur du collecteur sur la baie, pour un
compte en lecture seule. Verifier la connexion SSH avant de deployer.
host_template:
name: HW-IBM-Storwize-custom
alias: Materiel IBM Storwize
parents: [generic-active-host-custom]
macros:
- {name: STORWIZEUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: STORWIZEEXTRAOPTIONS, value: "", description: "Options supplementaires, dont la cle SSH"}
groupe_hote:
name: HG-HW-IBM-Storwize
alias: Baie IBM Storwize et FlashSystem (SSH)
notification:
perimetre: Baie IBM Storwize
calendrier:
name: TP-HW-IBM-Storwize-24x7
modele: 24x7
alias: Baie IBM Storwize et FlashSystem (SSH), en permanence
groupe: CG-HW-IBM-Storwize
criticite: Critique
impact: "Stockage partage en defaut, machines et applications menacees"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Hardware
alias: Hardware
description: Etat des composants de la baie
line: "$CENTREONPLUGINS$/centreon_ibm_storwize_ssh.pl --plugin=storage::ibm::storwize::ssh::plugin --mode=hardware --hostname=$HOSTADDRESS$ --ssh-username='$_HOSTSTORWIZEUSERNAME$' $_HOSTSTORWIZEEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Pool-Usage
alias: Pool-Usage
description: Occupation des pools de stockage
line: "$CENTREONPLUGINS$/centreon_ibm_storwize_ssh.pl --plugin=storage::ibm::storwize::ssh::plugin --mode=pool-usage --hostname=$HOSTADDRESS$ --ssh-username='$_HOSTSTORWIZEUSERNAME$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSTORWIZEEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: hw-netapp-ontap-snmp
name: Baie NetApp ONTAP (SNMP)
category: hardware
category: storage
status: to-verify
plugin: centreon_netapp_ontap_snmp.pl
description: Supervision d'une baie NetApp ONTAP en SNMP (etat global, volumes, disques, replication). Verifier les modes selon la version ONTAP.
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-NetApp-ONTAP-SNMP
alias: Baie NetApp ONTAP (SNMP)
notification:
perimetre: Baie NetApp ONTAP (SNMP)
calendrier:
name: TP-HW-NetApp-ONTAP-SNMP-24x7
modele: 24x7
alias: Baie NetApp ONTAP (SNMP), en permanence
groupe: CG-HW-NetApp-ONTAP-SNMP
criticite: Critique
impact: "Stockage partage en defaut"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Global-Status
alias: Global-Status
@@ -0,0 +1,55 @@
id: hw-purestorage-restapi
name: Baie Pure Storage (API REST)
category: storage
status: to-verify
plugin: centreon_purestorage_restapi.pl
description: Supervision d'une baie Pure Storage via son API REST (materiel, occupation, alertes).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
notes: |
Generer un jeton d'API pour un compte en lecture seule sur la baie.
host_template:
name: HW-PureStorage-custom
alias: Materiel Pure Storage
parents: [generic-active-host-custom]
macros:
- {name: PURETOKEN, value: "", description: "Jeton d'API", is_password: true}
- {name: PUREEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-PureStorage
alias: Baie Pure Storage (API REST)
notification:
perimetre: Baie Pure Storage
calendrier:
name: TP-HW-PureStorage-24x7
modele: 24x7
alias: Baie Pure Storage (API REST), en permanence
groupe: CG-HW-PureStorage
criticite: Critique
impact: "Stockage partage en defaut, machines et applications menacees"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Hardware
alias: Hardware
description: Etat des composants materiels
line: "$CENTREONPLUGINS$/centreon_purestorage_restapi.pl --plugin=storage::purestorage::restapi::plugin --mode=hardware --hostname=$HOSTADDRESS$ --api-token='$_HOSTPURETOKEN$' $_HOSTPUREEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Volume-Usage
alias: Volume-Usage
description: Occupation des volumes
line: "$CENTREONPLUGINS$/centreon_purestorage_restapi.pl --plugin=storage::purestorage::restapi::plugin --mode=volume-usage --hostname=$HOSTADDRESS$ --api-token='$_HOSTPURETOKEN$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTPUREEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Alarms
alias: Alarms
description: Alarmes actives sur la baie
line: "$CENTREONPLUGINS$/centreon_purestorage_restapi.pl --plugin=storage::purestorage::restapi::plugin --mode=alarms --hostname=$HOSTADDRESS$ --api-token='$_HOSTPURETOKEN$' $_HOSTPUREEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+54
View File
@@ -0,0 +1,54 @@
id: hw-qnap-snmp
name: NAS QNAP (SNMP)
category: storage
status: to-verify
plugin: centreon_qnap_snmp.pl
description: Supervision d'un NAS QNAP en SNMP (disques, volumes, ventilateurs, temperatures).
host_template:
name: HW-QNAP-SNMP-custom
alias: Materiel QNAP SNMP
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-QNAP-SNMP
alias: NAS QNAP (SNMP)
notification:
perimetre: NAS QNAP
calendrier:
name: TP-HW-QNAP-SNMP-24x7
modele: 24x7
alias: NAS QNAP (SNMP), en permanence
groupe: CG-HW-QNAP-SNMP
criticite: Majeure
impact: "Stockage et sauvegardes en defaut"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Hardware
alias: Hardware
description: Disques, ventilateurs et sondes de temperature
line: "$CENTREONPLUGINS$/centreon_qnap_snmp.pl --plugin=storage::qnap::snmp::plugin --mode=hardware --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --component='$_SERVICECOMPONENT$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: COMPONENT, value: ".*", description: "Composants a verifier (regex)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Storage
alias: Storage
description: Occupation des volumes
line: "$CENTREONPLUGINS$/centreon_qnap_snmp.pl --plugin=storage::qnap::snmp::plugin --mode=storage --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Cpu
alias: Cpu
description: Charge CPU du NAS
default: false
line: "$CENTREONPLUGINS$/centreon_qnap_snmp.pl --plugin=storage::qnap::snmp::plugin --mode=cpu --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-average='$_SERVICEWARNING$' --critical-average='$_SERVICECRITICAL$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: hw-synology-snmp
name: NAS Synology (SNMP)
category: hardware
category: storage
status: to-verify
plugin: centreon_synology_snmp.pl
description: Supervision d'un NAS Synology en SNMP (composants materiels, CPU, memoire, volumes). Verifier les modes selon la version DSM.
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-Synology-SNMP
alias: NAS Synology (SNMP)
notification:
perimetre: NAS Synology (SNMP)
calendrier:
name: TP-HW-Synology-SNMP-24x7
modele: 24x7
alias: NAS Synology (SNMP), en permanence
groupe: CG-HW-Synology-SNMP
criticite: Majeure
impact: "Stockage et sauvegardes en defaut"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Hardware
alias: Hardware
@@ -1,6 +1,6 @@
id: hw-apc-ups-snmp
name: Onduleur APC (SNMP)
category: hardware
category: ups-pdu
status: to-verify
plugin: centreon_apc_ups_snmp.pl
description: Supervision d'un onduleur APC en SNMP (batterie, lignes d'entree et de sortie). Verifier les modes disponibles selon le modele.
@@ -12,6 +12,21 @@ host_template:
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-APC-UPS-SNMP
alias: Onduleur APC (SNMP)
notification:
perimetre: Onduleur APC (SNMP)
calendrier:
name: TP-HW-APC-UPS-SNMP-24x7
modele: 24x7
alias: Onduleur APC (SNMP), en permanence
groupe: CG-HW-APC-UPS-SNMP
criticite: Critique
impact: "Alimentation electrique menacee"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Battery-Status
alias: Battery-Status
+58
View File
@@ -0,0 +1,58 @@
id: hw-ups-rfc1628
name: Onduleur standard (RFC 1628)
category: ups-pdu
status: to-verify
plugin: centreon_ups_standard_rfc1628_snmp.pl
description: Supervision de tout onduleur respectant la MIB standard UPS-MIB. Repli utile quand aucun pack constructeur ne correspond.
host_template:
name: HW-UPS-RFC1628-custom
alias: Materiel Onduleur RFC1628
parents: [generic-active-host-custom]
check_command: check_centreon_ping
check_command_args: "!3!200,20%!400,50%"
macros:
- {name: SNMPEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-HW-UPS-RFC1628
alias: Onduleur standard (RFC 1628)
notification:
perimetre: Onduleur standard (RFC 1628)
calendrier:
name: TP-HW-UPS-RFC1628-24x7
modele: 24x7
alias: Onduleur standard (RFC 1628), en permanence
groupe: CG-HW-UPS-RFC1628
criticite: Critique
impact: "Alimentation electrique menacee"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Battery-Status
alias: Battery-Status
description: Etat, charge et autonomie de la batterie
line: "$CENTREONPLUGINS$/centreon_ups_standard_rfc1628_snmp.pl --plugin=hardware::ups::standard::rfc1628::snmp::plugin --mode=battery-status --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-charge-remaining='$_SERVICEWARNINGCHARGE$' --critical-charge-remaining='$_SERVICECRITICALCHARGE$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNINGCHARGE, value: "50:", description: "Seuil warning sur la charge restante (%)"}
- {name: CRITICALCHARGE, value: "25:", description: "Seuil critical sur la charge restante (%)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Input-Lines
alias: Input-Lines
description: Tension et frequence des lignes d'entree
line: "$CENTREONPLUGINS$/centreon_ups_standard_rfc1628_snmp.pl --plugin=hardware::ups::standard::rfc1628::snmp::plugin --mode=input-lines --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Output-Lines
alias: Output-Lines
description: Charge et tension des lignes de sortie
line: "$CENTREONPLUGINS$/centreon_ups_standard_rfc1628_snmp.pl --plugin=hardware::ups::standard::rfc1628::snmp::plugin --mode=output-lines --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' --warning-load='$_SERVICEWARNINGLOAD$' --critical-load='$_SERVICECRITICALLOAD$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNINGLOAD, value: "70", description: "Seuil warning sur la charge (%)"}
- {name: CRITICALLOAD, value: "85", description: "Seuil critical sur la charge (%)"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Alarms
alias: Alarms
description: Alarmes remontees par l'onduleur
line: "$CENTREONPLUGINS$/centreon_ups_standard_rfc1628_snmp.pl --plugin=hardware::ups::standard::rfc1628::snmp::plugin --mode=alarms --hostname=$HOSTADDRESS$ --snmp-version='$_HOSTSNMPVERSION$' --snmp-community='$_HOSTSNMPCOMMUNITY$' $_HOSTSNMPEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: app-docker
name: Docker (API REST)
category: application
category: virtualization
status: to-verify
plugin: centreon_docker_restapi.pl
description: Supervision d'un hote Docker via son API REST (etat des conteneurs, consommation CPU et memoire). Verifier le nom du plugin selon la version installee.
@@ -12,6 +12,21 @@ host_template:
- {name: DOCKERPORT, value: "2376", description: "Port de l'API Docker"}
- {name: DOCKERPROTO, value: "https", description: "Protocole d'acces a l'API"}
- {name: DOCKEREXTRAOPTIONS, value: "", description: "Options supplementaires (certificats, api-version)"}
groupe_hote:
name: HG-App-Docker
alias: Docker (API REST)
notification:
perimetre: Docker (API REST)
calendrier:
name: TP-App-Docker-24x7
modele: 24x7
alias: Docker (API REST), en permanence
groupe: CG-App-Docker
criticite: Majeure
impact: "Conteneurs applicatifs arretes ou degrades"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Container-Status
alias: Container-Status
+50
View File
@@ -0,0 +1,50 @@
id: app-podman
name: Podman (API REST)
category: virtualization
status: to-verify
plugin: centreon_podman_restapi.pl
description: Supervision d'un hote Podman via son API REST (conteneurs, pods).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
host_template:
name: App-Podman-custom
alias: Applicatif Podman
parents: [generic-active-host-custom]
macros:
- {name: APIPORT, value: "443", description: "Port de l'API"}
- {name: APIPROTO, value: "https", description: "Protocole d'acces"}
- {name: APIUSERNAME, value: "centreon", description: "Compte de supervision"}
- {name: APIPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: APIEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Podman
alias: Podman (API REST)
notification:
perimetre: Podman (API REST)
calendrier:
name: TP-App-Podman-24x7
modele: 24x7
alias: Podman (API REST), en permanence
groupe: CG-App-Podman
criticite: Majeure
impact: "Conteneurs applicatifs arretes ou degrades"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Container-Usage
alias: Container-Usage
description: Consommation des conteneurs
line: "$CENTREONPLUGINS$/centreon_podman_restapi.pl --plugin=apps::podman::restapi::plugin --mode=container-usage --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-username='$_HOSTAPIUSERNAME$' --api-password='$_HOSTAPIPASSWORD$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "", description: "Seuil warning"}
- {name: CRITICAL, value: "", description: "Seuil critical"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Pod-Usage
alias: Pod-Usage
description: Etat des pods
line: "$CENTREONPLUGINS$/centreon_podman_restapi.pl --plugin=apps::podman::restapi::plugin --mode=pod-usage --hostname=$HOSTADDRESS$ --port='$_HOSTAPIPORT$' --proto='$_HOSTAPIPROTO$' --api-username='$_HOSTAPIUSERNAME$' --api-password='$_HOSTAPIPASSWORD$' $_HOSTAPIEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
+68
View File
@@ -0,0 +1,68 @@
id: app-proxmox
name: Proxmox VE (API REST)
category: virtualization
status: to-verify
plugin: centreon_proxmox_ve_api.pl
description: Supervision d'un cluster Proxmox VE via son API REST (noeuds, machines virtuelles, stockage, quorum).
prerequis:
paquets:
debian: [libwww-perl, libjson-xs-perl]
rhel: [perl-libwww-perl, perl-JSON-XS]
notes: |
Creer un utilisateur de supervision dans Proxmox avec le role PVEAuditor :
pveum user add centreon@pve --password '...'
pveum acl modify / --users centreon@pve --roles PVEAuditor
host_template:
name: App-Proxmox-custom
alias: Applicatif Proxmox VE
parents: [generic-active-host-custom]
macros:
- {name: PVEPORT, value: "8006", description: "Port de l'API"}
- {name: PVEUSERNAME, value: "centreon@pve", description: "Compte de supervision"}
- {name: PVEPASSWORD, value: "", description: "Mot de passe du compte", is_password: true}
- {name: PVEEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
groupe_hote:
name: HG-App-Proxmox
alias: Proxmox VE (API REST)
notification:
perimetre: Proxmox VE (API REST)
calendrier:
name: TP-App-Proxmox-24x7
modele: 24x7
alias: Proxmox VE (API REST), en permanence
groupe: CG-App-Proxmox
criticite: Critique
impact: "Hyperviseur en defaut, machines virtuelles menacees"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Cluster-Status
alias: Cluster-Status
description: Quorum et etat general du cluster
line: "$CENTREONPLUGINS$/centreon_proxmox_ve_api.pl --plugin=apps::proxmox::ve::restapi::plugin --mode=cluster-status --hostname=$HOSTADDRESS$ --port='$_HOSTPVEPORT$' --api-username='$_HOSTPVEUSERNAME$' --api-password='$_HOSTPVEPASSWORD$' $_HOSTPVEEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Node-Usage
alias: Node-Usage
description: Consommation CPU, memoire et disque des noeuds
line: "$CENTREONPLUGINS$/centreon_proxmox_ve_api.pl --plugin=apps::proxmox::ve::restapi::plugin --mode=node-usage --hostname=$HOSTADDRESS$ --port='$_HOSTPVEPORT$' --api-username='$_HOSTPVEUSERNAME$' --api-password='$_HOSTPVEPASSWORD$' --warning-cpu='$_SERVICEWARNINGCPU$' --critical-cpu='$_SERVICECRITICALCPU$' $_HOSTPVEEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNINGCPU, value: "80", description: "Seuil warning CPU en %"}
- {name: CRITICALCPU, value: "90", description: "Seuil critical CPU en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Vm-Usage
alias: Vm-Usage
description: Etat et consommation des machines virtuelles
line: "$CENTREONPLUGINS$/centreon_proxmox_ve_api.pl --plugin=apps::proxmox::ve::restapi::plugin --mode=vm-usage --hostname=$HOSTADDRESS$ --port='$_HOSTPVEPORT$' --api-username='$_HOSTPVEUSERNAME$' --api-password='$_HOSTPVEPASSWORD$' --filter-name='$_SERVICEFILTERNAME$' $_HOSTPVEEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: FILTERNAME, value: "", description: "Filtre sur le nom de la machine"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
- name: Storage-Usage
alias: Storage-Usage
description: Occupation des espaces de stockage
line: "$CENTREONPLUGINS$/centreon_proxmox_ve_api.pl --plugin=apps::proxmox::ve::restapi::plugin --mode=storage-usage --hostname=$HOSTADDRESS$ --port='$_HOSTPVEPORT$' --api-username='$_HOSTPVEUSERNAME$' --api-password='$_HOSTPVEPASSWORD$' --warning-usage-prct='$_SERVICEWARNING$' --critical-usage-prct='$_SERVICECRITICAL$' $_HOSTPVEEXTRAOPTIONS$ $_SERVICEEXTRAOPTIONS$"
macros:
- {name: WARNING, value: "80", description: "Seuil warning en %"}
- {name: CRITICAL, value: "90", description: "Seuil critical en %"}
- {name: EXTRAOPTIONS, value: "", description: "Options supplementaires"}
@@ -1,6 +1,6 @@
id: app-vmware-esx
name: VMware ESXi (connecteur Centreon VMware)
category: application
category: virtualization
status: to-verify
plugin: centreon_vmware_connector_client.pl
description: Supervision d'un hote ESXi via le connecteur Centreon VMware. Le connecteur doit etre installe et configure avec l'acces vCenter.
@@ -14,6 +14,28 @@ host_template:
- {name: VMWARECONTAINER, value: "default", description: "Nom du container declare dans le connecteur"}
- {name: VMWAREESXHOSTNAME, value: "", description: "Nom de l'hote ESXi dans le vCenter"}
- {name: VMWAREEXTRAOPTIONS, value: "", description: "Options supplementaires passees au plugin"}
prerequis:
paquets:
debian: [centreon-plugin-virtualization-vmware2-connector-daemon]
rhel: [centreon-plugin-virtualization-vmware2-connector-daemon]
notes: |
Le connecteur Centreon VMware doit tourner et declarer un container
pointant sur le vCenter, avec un compte en lecture seule.
groupe_hote:
name: HG-App-VMware-ESX
alias: VMware ESXi (connecteur Centreon VMware)
notification:
perimetre: VMware ESXi (connecteur Centreon VMware)
calendrier:
name: TP-App-VMware-ESX-24x7
modele: 24x7
alias: VMware ESXi (connecteur Centreon VMware), en permanence
groupe: CG-App-VMware-ESX
criticite: Critique
impact: "Hyperviseur en defaut, machines virtuelles menacees"
options_hote: d,u,r
options_service: w,c,r
intervalle: 30
services:
- name: Host-Status
alias: Host-Status
+81 -15
View File
@@ -18,12 +18,52 @@ services:
ENCLUME_CATALOG: /catalogue/actuel
GUNICORN_WORKERS: ${GUNICORN_WORKERS:-2}
TZ: ${TZ:-Europe/Paris}
ENCLUME_URL_PUBLIQUE: https://${ENCLUME_DOMAINE}
# Sessions. Sans cle, elles sont perdues a chaque redemarrage.
ENCLUME_SECRET_KEY: ${ENCLUME_SECRET_KEY:?definir ENCLUME_SECRET_KEY}
# Base : sans elle, ni partage ni comptes, l'editeur fonctionne quand meme.
# Elements separes plutot qu'une URL : un mot de passe contenant @ : / ?
# casserait une URL, ici il est encode par l'application.
ENCLUME_DB_HOTE: db
ENCLUME_DB_PORT: "5432"
ENCLUME_DB_NOM: enclume
ENCLUME_DB_UTILISATEUR: enclume
ENCLUME_DB_MOTDEPASSE: ${POSTGRES_PASSWORD:?definir POSTGRES_PASSWORD}
ENCLUME_PARTAGE_JOURS: ${ENCLUME_PARTAGE_JOURS:-90}
# Mentions legales. Sans ces valeurs, la page indique ce qui manque.
ENCLUME_EDITEUR: ${ENCLUME_EDITEUR:-}
ENCLUME_CONTACT: ${ENCLUME_CONTACT:-}
ENCLUME_HEBERGEUR: ${ENCLUME_HEBERGEUR:-}
ENCLUME_DEPOT: ${ENCLUME_DEPOT:-}
# Connexion optionnelle, deleguee a Authentik qui federe GitHub et Google.
ENCLUME_OIDC_METADATA: ${ENCLUME_OIDC_METADATA:-}
ENCLUME_OIDC_CLIENT_ID: ${ENCLUME_OIDC_CLIENT_ID:-}
ENCLUME_OIDC_CLIENT_SECRET: ${ENCLUME_OIDC_CLIENT_SECRET:-}
ENCLUME_INSCRIPTION_OUVERTE: ${ENCLUME_INSCRIPTION_OUVERTE:-0}
ENCLUME_ADMIN_GROUPE: ${ENCLUME_ADMIN_GROUPE:-enclume-admins}
ENCLUME_ADMIN_COMPTES: ${ENCLUME_ADMIN_COMPTES:-}
# Depot du catalogue : la moderation y ouvre des demandes de fusion.
ENCLUME_GITEA_URL: ${ENCLUME_GITEA_URL:-}
ENCLUME_GITEA_TOKEN: ${ENCLUME_GITEA_TOKEN:-}
ENCLUME_GITEA_PROPRIETAIRE: ${ENCLUME_GITEA_PROPRIETAIRE:-}
ENCLUME_GITEA_DEPOT: ${ENCLUME_GITEA_DEPOT:-}
depends_on:
db:
condition: service_healthy
# Gitea et ce conteneur sont souvent sur le meme reseau. Faire sortir la
# requete par un tunnel pour revenir chez soi l'expose aux protections
# placees devant lui, qui rejettent les clients non navigateurs. Decommenter
# et adapter : le nom reste le meme, donc le certificat aussi, seul le
# chemin reseau change.
# extra_hosts:
# - "gitea.exemple.com:192.168.1.10"
volumes:
- catalogue:/catalogue:ro
networks: [back_network_enclume, db_network_enclume, traefik_front_network]
read_only: true
tmpfs:
- /tmp:size=32m,mode=1777
- /app/.gunicorn:size=8m,mode=0700,uid=10001,gid=10001
security_opt: ["no-new-privileges:true"]
cap_drop: [ALL]
deploy:
@@ -33,19 +73,42 @@ services:
driver: json-file
options: {max-size: "10m", max-file: "3"}
labels:
traefik.enable: "true"
traefik.docker.network: traefik_front_network
traefik.http.routers.enclume.rule: Host(`${ENCLUME_DOMAINE:?definir ENCLUME_DOMAINE}`)
traefik.http.routers.enclume.entrypoints: websecure
traefik.http.routers.enclume.tls.certresolver: ${TRAEFIK_RESOLVER:-cloudflare}
traefik.http.routers.enclume.middlewares: enclume-entetes,enclume-limite
traefik.http.services.enclume.loadbalancer.server.port: "8080"
traefik.http.middlewares.enclume-entetes.headers.stsSeconds: "31536000"
traefik.http.middlewares.enclume-entetes.headers.stsIncludeSubdomains: "true"
traefik.http.middlewares.enclume-entetes.headers.frameDeny: "true"
traefik.http.middlewares.enclume-entetes.headers.contentTypeNosniff: "true"
traefik.http.middlewares.enclume-limite.ratelimit.average: "60"
traefik.http.middlewares.enclume-limite.ratelimit.burst: "120"
# Watchtower volontairement absent : les versions sont epinglees dans .env
# et le retour arriere repose sur ce controle. Une mise a jour automatique
# le rendrait illusoire.
- "traefik.enable=true"
- "traefik.docker.network=traefik_front_network"
# HTTP
- "traefik.http.routers.enclume-http.rule=Host(`${ENCLUME_DOMAINE:?definir ENCLUME_DOMAINE}`)"
- "traefik.http.routers.enclume-http.entrypoints=http"
- "traefik.http.routers.enclume-http.priority=49"
# HTTPS
- "traefik.http.routers.enclume-https.rule=Host(`${ENCLUME_DOMAINE}`)"
- "traefik.http.routers.enclume-https.entrypoints=https"
- "traefik.http.routers.enclume-https.tls=true"
- "traefik.http.routers.enclume-https.priority=50"
- "traefik.http.routers.enclume-https.service=enclume-https-service"
- "traefik.http.routers.enclume-https.middlewares=enclume-middlewares,enclume-limite"
- "traefik.http.routers.enclume-https.observability.accesslogs=true"
- "traefik.http.routers.enclume-https.observability.metrics=true"
- "traefik.http.routers.enclume-https.observability.tracing=true"
# Middleware
- "traefik.http.middlewares.enclume-middlewares.headers.STSSeconds=15552000"
- "traefik.http.middlewares.enclume-middlewares.headers.forceSTSHeader=true"
- "traefik.http.middlewares.enclume-middlewares.headers.STSIncludeSubdomains=true"
- "traefik.http.middlewares.enclume-middlewares.headers.STSPreload=true"
- "traefik.http.middlewares.enclume-middlewares.headers.frameDeny=true"
# Site public : une limite de debit evite qu'un script ne monopolise la generation.
- "traefik.http.middlewares.enclume-limite.ratelimit.average=60"
- "traefik.http.middlewares.enclume-limite.ratelimit.burst=120"
# Service
- "traefik.http.services.enclume-https-service.loadbalancer.server.port=8080"
# Homepage
- "homepage.group=Supervision"
- "homepage.name=Enclume"
- "homepage.icon=centreon.png"
- "homepage.href=https://${ENCLUME_DOMAINE}"
- "homepage.description=Generateur CLAPI Centreon"
catalog-sync:
image: ${ENCLUME_REGISTRY:-registry.tips-of-mine.com}/enclume/catalog-sync:${ENCLUME_TAG:?definir ENCLUME_TAG dans .env}
@@ -57,6 +120,9 @@ services:
CATALOG_DEST: /catalogue
SYNC_INTERVAL: ${SYNC_INTERVAL:-300}
RELOAD_URL: http://web:8080/recharger
depends_on:
web:
condition: service_healthy
volumes:
- catalogue:/catalogue
networks: [back_network_enclume]
@@ -68,8 +134,8 @@ services:
driver: json-file
options: {max-size: "5m", max-file: "2"}
# Utilisee a partir du chantier 2 (liens de partage, projets enregistres).
# L'application fonctionne sans, tant que ENCLUME_DATABASE_URL n'est pas defini.
# Partages, projets enregistres et soumissions de packs.
# L'application demarre sans, tant que ENCLUME_DATABASE_URL n'est pas defini.
db:
image: postgres:16.4-alpine
restart: unless-stopped
+20 -4
View File
@@ -19,7 +19,8 @@ if [ -z "${CATALOG_REPO:-}" ]; then
while true; do sleep 3600; done
fi
TRAVAIL=/tmp/depot
# Emplacement du clone de travail, surchargeable pour les tests.
TRAVAIL=${CATALOG_TRAVAIL:-/tmp/depot}
TEMOIN=/tmp/derniere-revision-confirmee
# Previent l'application, et retient si elle a repondu. Tant que la reponse
@@ -39,6 +40,13 @@ prevenir_application() {
}
sync_une_fois() {
# Un clone existant dont l'origine a change tirerait indefiniment depuis
# l'ancien depot : on le refait plutot que de le mettre a jour.
if [ -d "$TRAVAIL/.git" ]; then
ORIGINE=$(git -C "$TRAVAIL" remote get-url origin 2>/dev/null || echo "")
[ "$ORIGINE" = "$CATALOG_REPO" ] || rm -rf "$TRAVAIL"
fi
if [ -d "$TRAVAIL/.git" ]; then
git -C "$TRAVAIL" fetch --quiet --depth 1 origin "$CATALOG_BRANCH" || return 1
git -C "$TRAVAIL" reset --quiet --hard "origin/$CATALOG_BRANCH" || return 1
@@ -66,9 +74,17 @@ sync_une_fois() {
cp -a "$SOURCE"/. "$CIBLE.partiel"/ || return 1
mv "$CIBLE.partiel" "$CIBLE" || return 1
# Bascule atomique du lien, puis menage des anciennes revisions.
ln -sfn "$CIBLE" "$CATALOG_DEST/actuel.neuf"
mv -f "$CATALOG_DEST/actuel.neuf" "$CATALOG_DEST/actuel" || return 1
# Bascule du lien. Surtout pas "mv vers actuel" : quand actuel est un lien
# vers un repertoire, mv le suit et depose le fichier a l'interieur au lieu
# de remplacer le lien. ln -sfn remplace le lien lui-meme, sans le suivre.
ln -sfn "$CIBLE" "$CATALOG_DEST/actuel" || return 1
rm -rf "$CATALOG_DEST"/rev-*/actuel.neuf "$CATALOG_DEST/actuel.neuf"
# Verification : sans elle, une bascule ratee passerait pour un succes.
if [ "$(readlink "$CATALOG_DEST/actuel")" != "$CIBLE" ]; then
echo "catalog-sync : la bascule du lien a echoue" >&2
return 1
fi
ls -1dt "$CATALOG_DEST"/rev-* 2>/dev/null | tail -n +$((REVISIONS_CONSERVEES + 1)) | while read -r vieux; do
rm -rf "$vieux"
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
# Demarrage de l'application.
#
# Les migrations tournent avant gunicorn, et un echec arrete le conteneur :
# une base a moitie migree derriere une application qui repond serait pire
# qu'une indisponibilite visible.
set -eu
# Deux facons de declarer la base : une URL complete, ou les elements separes.
# Tester une seule des deux sauterait silencieusement les migrations.
if [ -n "${ENCLUME_DATABASE_URL:-}" ] || [ -n "${ENCLUME_DB_HOTE:-}" ]; then
echo "enclume : migration de la base"
alembic upgrade head
else
echo "enclume : aucune base configuree, mode sans etat"
fi
exec gunicorn \
--bind 0.0.0.0:8080 \
--workers "${GUNICORN_WORKERS:-2}" \
--timeout "${GUNICORN_TIMEOUT:-30}" \
--access-logfile - \
--error-logfile - \
--forwarded-allow-ips '*' \
'enclume.webapp:create_app()'
+185
View File
@@ -0,0 +1,185 @@
# Comptes, partage et modération
Trois fonctionnalités s'activent indépendamment. Aucune n'est obligatoire : sans base de
données, sans OIDC et sans jeton Gitea, Enclume reste l'éditeur qui génère du CLAPI. C'est
ce qui permet à n'importe qui de l'auto-héberger sans rien configurer.
| Fonction | Ce qu'il faut | Sans ça |
|---|---|---|
| Partage par lien | `ENCLUME_DATABASE_URL` | bouton absent |
| Comptes et projets enregistrés | base + OIDC | site utilisable, sans connexion |
| Soumission de packs | base + OIDC | contributions par pull request uniquement |
| Publication des packs acceptés | jeton Gitea | modération possible, publication non |
`/health` annonce l'état réel de chacune.
## Authentik
Un seul fournisseur est déclaré côté Enclume. C'est Authentik qui fédère GitHub, Google ou
tout autre fournisseur social : en ajouter un plus tard ne demande aucun redéploiement.
**Créer le fournisseur** — Applications → Fournisseurs → Créer → OAuth2/OpenID.
- Type de client : **Confidentiel**
- URI de redirection, en correspondance stricte : `https://<domaine>/connexion/retour`
- Portées : `openid`, `email`, `profile`
- Noter l'identifiant client et le secret
**Créer l'application** — Applications → Applications → Créer. Le **slug** compte : c'est lui
qui apparaît dans l'URL de découverte.
```
ENCLUME_OIDC_METADATA=https://authentik.<domaine>/application/o/<slug>/.well-known/openid-configuration
ENCLUME_OIDC_CLIENT_ID=...
ENCLUME_OIDC_CLIENT_SECRET=...
```
### En cas de « Redirect URI Error »
Authentik compare au caractère près l'URI reçue à celle déclarée. Demandez à l'application ce
qu'elle envoie :
```bash
curl -s https://<domaine>/health | python3 -m json.tool | grep uri_de_retour
```
La valeur renvoyée est exactement celle à déclarer dans **le fournisseur**, champ « URIs de
redirection », en correspondance **Stricte**. Attention à ne pas la saisir dans « URI de
déconnexion », qui est un champ voisin et sans rapport.
La page d'erreur porte aussi dans son adresse le paramètre `redirect_uri=` : c'est la même
information, vue depuis le navigateur.
- Une barre oblique finale, un `http` au lieu de `https`, un sous-domaine différent : tout
écart compte.
- Si l'URI reçue est en `http://` ou sur un nom d'hôte interne, c'est que les en-têtes du
proxy ne sont pas honorés. Vérifier que `ENCLUME_URL_PUBLIQUE` est bien définie dans le
compose : elle fait autorité et supprime toute ambiguïté.
**Le groupe de modération.** Enclume lit la revendication `groups` du jeton. Depuis
Authentik 2026.8, les correspondances de portée par défaut l'exposent déjà pour certains
fournisseurs ; si ce n'est pas le cas chez vous, créer une correspondance de portée
(Personnalisation → Property Mappings → Scope Mapping), nom de portée `groups` :
```python
return {"groups": [group.name for group in request.user.groups.all()]}
```
La relation `request.user.ak_groups` utilisée dans les exemples plus anciens est dépréciée
depuis la 2026.8 et déclenche un avertissement de configuration.
Rattacher cette portée au fournisseur, puis créer le groupe de modération et s'y inscrire.
Le nom du groupe se règle par `ENCLUME_ADMIN_GROUPE`, il n'a pas à s'appeler
`enclume-admins`.
Le temps de mettre ça en place, `[email protected]` donne l'accès
à la modération sur la seule foi de l'adresse. À vider ensuite.
## Qui peut obtenir un compte
Par défaut, `ENCLUME_INSCRIPTION_OUVERTE=0` : le site n'affiche aucun bouton de connexion
public, mais un bouton « Contribuer » qui explique que l'éditeur fonctionne sans compte et
que les packs se proposent par demande de fusion. Un lien discret « Se connecter (équipe) »
reste disponible dans cette fenêtre pour les mainteneurs.
Ce réglage existe parce que promettre une connexion à quelqu'un qui ne peut pas obtenir de
compte — annuaire sans source externe, inscription fermée — est une impasse silencieuse.
Passez-le à `1` une fois les sources et le flux d'enrôlement en place, ci-dessous.
## Ouvrir le site à d'autres que vous
Si Enclume doit accueillir des visiteurs extérieurs, deux points sont à traiter côté
Authentik, et aucun n'est automatique :
- **Des sources externes.** GitHub, Google ou autre, déclarées en tant que sources OAuth.
Sans elles, seuls les comptes de votre annuaire peuvent se connecter.
- **Un flux d'enrôlement rattaché à ces sources.** C'est lui qui crée le compte local à la
première connexion. Beaucoup d'installations suppriment le flux d'enrôlement par défaut,
précisément parce qu'il ouvre l'auto-inscription : il faut alors en créer un dédié, lié
aux sources et non joignable directement par URL.
- **Ne pas cloisonner l'application par groupe.** Une liaison de groupe sur l'application
Enclume interdirait la connexion à tout visiteur qui n'en est pas membre.
Vérifiez aussi ce que votre flux d'authentification impose : une validation MFA obligatoire
a du sens pour vos comptes internes, beaucoup moins pour un visiteur qui veut seulement
enregistrer un projet.
Rien de tout cela n'est nécessaire si le site reste à usage interne : la connexion demeure
facultative, et un visiteur non connecté conserve l'éditeur, la génération et le partage.
## Le jeton Gitea
Un jeton d'accès personnel sur le compte qui ouvrira les demandes de fusion, avec la portée
`write:repository` sur le dépôt du catalogue. Publier un pack accepté crée une branche, y
dépose le fichier YAML et ouvre une pull request — **jamais un push sur la branche
principale**. Tu relis dans Gitea avant de fusionner.
### Si la publication est refusée
Le dépôt du catalogue fait foi : publier crée un fichier, et Gitea refuse d'en créer un qui
existe déjà. Un pack proposé sous un identifiant déjà présent doit donc être refusé, avec
pour motif la mise à jour du pack existant — qui passe par une pull request ordinaire, pas
par la modération.
### Si la publication échoue en 403
Une protection placée devant Gitea — Cloudflare et son contrôle d'intégrité du navigateur,
par exemple — rejette les clients qui ne sont pas des navigateurs. Le symptôme est un
`HTTP 403 : error code: 1010`, et la requête n'atteint jamais Gitea.
La sortie consiste à joindre Gitea directement, sans passer par la protection :
```yaml
extra_hosts:
- "gitea.exemple.com:192.168.1.10"
```
Le nom d'hôte est inchangé, donc le certificat reste valide ; seul le chemin réseau change.
Alternative : pointer `ENCLUME_GITEA_URL` sur une adresse interne, au prix d'un certificat
qui ne correspondra plus.
## Ce qui n'est jamais stocké
Les macros marquées « mot de passe » sont vidées avant toute écriture en base : partage,
projet enregistré, soumission. Un site public n'a aucune raison de détenir le mot de passe
MySQL de quelqu'un. L'avertissement affiché au partage le rappelle à l'utilisateur.
## La connexion a la base
Le compose passe l'hôte, le port, la base, l'utilisateur et le mot de passe **séparément**,
et l'application assemble l'URL en encodant ce qui doit l'être. Un mot de passe contenant
`@`, `:`, `/` ou `#` ne pose donc aucun problème — alors qu'écrit directement dans une URL,
il la disloquerait silencieusement.
`ENCLUME_DATABASE_URL` reste accepté et prend le pas, pour pointer une base externe.
## Migrations
Le conteneur `web` exécute `alembic upgrade head` à son démarrage, puis lance gunicorn. Un
échec de migration arrête le conteneur : une base à moitié migrée derrière une application
qui répond serait pire qu'une indisponibilité visible.
**Règle d'écriture des migrations** : on ajoute, on ne retire jamais dans la même version que
le code qui cesse d'utiliser une colonne. La suppression arrive une version plus tard. Sans
cette discipline, revenir à l'image précédente casse l'application — et tout l'intérêt des
tags immuables disparaît.
Sauvegarde avant une montée de version qui touche au schéma :
```bash
docker compose exec -T db pg_dump -U enclume enclume | zstd > enclume-$(date +%F).sql.zst
```
## Les limites en place
| Réglage | Défaut | Rôle |
|---|---|---|
| `ENCLUME_PARTAGE_JOURS` | 90 | expiration des liens |
| `ENCLUME_PROJETS_PAR_COMPTE` | 50 | projets enregistrés par compte |
| `ENCLUME_SOUMISSIONS_PAR_JOUR` | 10 | soumissions par compte et par jour |
| `ENCLUME_TAILLE_MAX_PACK` | 256 ko | taille d'un YAML soumis |
| `ENCLUME_TAILLE_MAX_PROJET` | 2 Mo | taille d'un projet |
Les identifiants de partage font 12 caractères tirés au hasard, soit 72 bits : ils ne
s'énumèrent pas. Les liens expirés sont purgés à chaque nouveau partage.
+107
View File
@@ -0,0 +1,107 @@
# Conventions et revue avant livraison
Ce fichier existe pour que le projet reste cohérent d'une version à l'autre, et pour qu'une
anomalie soit trouvée sur le poste de développement plutôt qu'après soixante minutes de
construction.
## Revue avant chaque livraison
Dans cet ordre, sans exception, y compris pour un correctif d'une ligne :
```bash
python -m ruff check . # analyse statique, zéro signalement toléré
python -m pytest -q # la suite complète
node --check enclume/static/*.js # syntaxe des scripts
sh tests/interface.sh # l'editeur, dans un DOM headless
sh -n docker/*.sh # syntaxe des scripts shell
python -c "import yaml,glob;[yaml.safe_load(open(f)) for f in glob.glob('catalog/**/*.yml',recursive=True)]"
docker compose -f compose.yaml config > /dev/null
```
Puis, dans un environnement vierge — c'est ce qui a manqué le jour où `requests` a cassé la
CI :
```bash
python -m venv /tmp/vierge && /tmp/vierge/bin/pip install -r requirements.txt pytest
/tmp/vierge/bin/python -m pytest -q
```
Et enfin la revue humaine, qui ne s'automatise pas :
- toute ressource référencée par un gabarit existe-t-elle réellement ? (un test le vérifie
désormais, parce que l'oubli a déjà eu lieu)
- les noms d'hôte, de dépôt et de domaine cités dans la documentation et les exemples sont-ils
encore les bons ? Ni `ruff` ni les tests ne lisent le Markdown.
- une variable nouvelle est-elle présente dans `.env.example`, dans `compose.yaml` **et**
documentée ?
- une valeur venant de l'utilisateur peut-elle contenir un caractère qui casse le format où
on l'insère ? Point-virgule pour le CLAPI, `@` et `:` pour une URL de connexion, guillemet
simple pour le shell, `%` pour un fichier ini lu par configparser. **Quatre** incidents sur
ce seul motif — c'est le premier endroit où regarder.
- une modification a-t-elle **réellement** été appliquée ? Une correction annoncée en 1.11.1
n'avait jamais pris : le texte recherché avait changé entre-temps. Relire le fichier après
l'édition, et faire passer un test par le chemin réel, pas seulement par la couche voisine.
- une valeur déjà encodée traverse-t-elle un second format qui réinterprète son encodage ?
C'est la variante du piège précédent : `%40` est correct dans une URL, et devient une
interpolation dans un ini.
- ce qui est écrit en base a-t-il traversé `strip_secrets` ?
## Un principe : le moins de saisie libre possible
Chaque champ de texte libre est une occasion de faute de frappe qui ne se verra qu'au
déploiement sur le central. Un champ nouveau doit donc, dans l'ordre de préférence :
1. **une liste fermée** quand les valeurs possibles sont connues et finies — un fuseau
horaire, un type de commande, une version SNMP ;
2. **une liste ouverte avec suggestions** quand des valeurs existent déjà sur le central que
nous ne connaissons pas — un modèle parent, un groupe d'hôtes, une commande de
vérification ;
3. **la saisie libre** seulement pour ce qui est propre à l'utilisateur : un nom, une
description, un seuil.
Et quand une valeur juste est majoritairement la même, elle est **préremplie**. Un projet
vide part avec `/usr/lib/centreon/plugins`, `generic-active-host-custom` et `Central` :
l'utilisateur corrige si son installation diffère, il ne devine pas.
## Nommage
| Objet | Règle | Exemple |
|---|---|---|
| Modules Python | français, minuscules, sans accent | `routes_donnees.py` |
| Fonctions et variables | français, `snake_case` | `utilisateur_courant`, `_repertoire_catalogue` |
| Classes | français, `PascalCase` | `Soumission`, `Prerequis` |
| Variables d'environnement | préfixe `ENCLUME_`, majuscules | `ENCLUME_DB_MOTDEPASSE` |
| Routes d'API | français, pluriel | `/api/soumissions`, `/api/partages` |
| Identifiants HTML | français, `kebab-case` | `btn-serveur-ouvrir`, `filtre-statut` |
| Fichiers statiques | français | `editeur.js`, `moderation.js` |
| Tables | français, pluriel | `utilisateurs`, `partages` |
| Packs du catalogue | `<famille>-<techno>[-<protocole>]` | `os-linux-snmp`, `hw-dell-idrac-snmp` |
| Modèles d'hôte générés | `<Famille>-<Techno>-custom` | `OS-Linux-SNMP-custom` |
| Modèles de service | `<Famille>-<Techno>-<Sonde>` | `OS-Linux-SNMP-Cpu` |
| Images | `<registre>/enclume/<composant>` | `.../enclume/catalog-sync` |
| Branches de soumission | `pack/<id>-<numéro>` | `pack/app-rabbitmq-7` |
Les commentaires et la documentation sont en français. Le code source reste sans accents,
par choix, pour éviter toute question d'encodage dans les conteneurs.
## Versions
Sémantique stricte, parce que la rétention Harbor et le retour arrière s'y appuient :
- **correctif** (`1.1.2`) : rien de nouveau, rien qui change de nom
- **mineure** (`1.2.0`) : fonctionnalité, nouvelle variable, migration de schéma
- **majeure** (`2.0.0`) : rupture pour qui héberge déjà — variable supprimée, format de
projet incompatible
Une migration de schéma n'ajoute que des colonnes et des tables. Une suppression attend la
version suivante, sinon revenir à l'image précédente casse l'application.
## Coût de construction
L'arm64 passe par l'émulation QEMU et coûte l'essentiel du temps de construction. Il n'est
donc produit **que sur un tag de version** ; un simple push sur `main` ne construit que
l'amd64. Le cache de couches vit dans Harbor, à côté des images : tant que
`requirements.txt` ne change pas, l'installation des dépendances est reprise du cache.
Conséquence pratique : itérer sur `main` est rapide, publier une version reste lent. Autant
grouper les corrections avant de taguer.
+6 -6
View File
@@ -17,15 +17,15 @@ sortant depuis Docker, et personne ne les joint de l'extérieur.
## Première installation
```bash
git clone https://gitea.tips-of-mine.com/hubert/enclume.git
cd enclume
cp .env.example .env # renseigner ENCLUME_TAG, ENCLUME_DOMAINE, POSTGRES_PASSWORD
git clone https://gitea.tips-of-mine.com/Tips-Of-Mine/Enclume.git
cd Enclume
cp .env.example .env # renseigner ENCLUME_TAG, ENCLUME_DOMAINE, POSTGRES_PASSWORD, ENCLUME_SECRET_KEY
docker compose pull
docker compose up -d
curl -s https://clapi.tips-of-mine.com/sante
curl -s https://enclume.tips-of-mine.com/health
```
`/sante` renvoie la version et le commit de l'image en cours : c'est la source de vérité
`/health` renvoie la version et le commit de l'image en cours : c'est la source de vérité
sur ce qui tourne réellement.
## Mise à jour
@@ -35,7 +35,7 @@ Une évolution donne une image, jamais un `docker compose build` sur le serveur.
```bash
sed -i 's/^ENCLUME_TAG=.*/ENCLUME_TAG=1.4.0/' .env
docker compose pull && docker compose up -d
curl -s https://clapi.tips-of-mine.com/sante | grep 1.4.0
curl -s https://enclume.tips-of-mine.com/health | grep 1.1.4
```
## Retour arrière
+1 -1
View File
@@ -86,7 +86,7 @@ Puis sur le serveur, dans le répertoire du compose :
```bash
cp .env.example .env # renseigner ENCLUME_TAG=1.0.0 et le domaine
docker compose pull && docker compose up -d
curl -s https://<domaine>/sante
curl -s https://<domaine>/health
```
## Réseau Traefik
+152
View File
@@ -0,0 +1,152 @@
# Notifications par périmètre
Un modèle de service sans notification ne sert à rien en production. Enclume génère donc
aussi la chaîne de notification : le calendrier, la commande, les paramètres des contacts,
et le script PHP qui met en forme le message.
## Les packs livrent leur chaîne
Chaque pack du catalogue déclare son périmètre : le calendrier adapté à sa criticité, un
groupe de contacts nommé `CG-<Famille>-<Techno>`, et l'impact métier d'une panne. Importer le
pack LDAP crée donc le groupe `CG-App-LDAP`, rattache le modèle d'hôte et tous les modèles de
service à un périmètre en 24x7, et remplit le message avec « Authentification et annuaire
indisponibles ».
Il reste une chose à faire de votre côté : **mettre des contacts dans le groupe**. Enclume
crée le groupe vide, faute de connaître vos utilisateurs.
### Chaque pack apporte son calendrier
Un pack ne réutilise pas les calendriers du central : il crée le sien,
`TP-App-Apache-24x7`, `TP-HW-Printer-RFC3805-Heures-Ouvrees`. Ajuster les plages d'une
technologie ne touche alors qu'elle, et non tout ce qui pointait `24x7`.
Le rythme copié à la création est `24x7` pour ce dont la panne réveille quelqu'un,
`Heures-Ouvrees` sinon. Les plages restent modifiables ensuite, comme n'importe quel objet
du projet.
Si vous préférez viser un calendrier existant sur votre central — `24x7`, `workhours` —
saisissez-le dans le périmètre : il apparaîtra dans le projet marqué « Centreon » et ne sera
pas recréé, `TP;ADD` échouant sur un objet existant.
## Le principe
Un **périmètre** regroupe ce qui différencie réellement un domaine d'un autre :
| Élément | Rôle |
|---|---|
| Calendrier | quand la notification a le droit de partir (objet `TP` de Centreon) |
| Destinataires | contacts existants et groupe à créer |
| États déclencheurs | distincts pour l'hôte et le service |
| Contexte métier | application, responsable, criticité, impact, procédure de reprise |
| Sujets | pour l'hôte et pour le service, avec les macros de Centreon |
Un incident sur la chaîne de facturation et un disque plein sur un serveur de rebond
n'appellent ni le même destinataire, ni le même horaire, ni le même message. C'est
exactement ce que le périmètre permet de séparer.
## Ce qui est généré
Pour chaque périmètre :
- deux commandes de type `notif`, `<Périmètre>-Notify-Host` et `-Notify-Service` ;
- un script `notifications/notif-<périmètre>.php`, avec le shebang
`#!/usr/bin/php -c /etc/php.ini` ;
- les paramètres de notification de chaque contact : `hostnotifperiod`, `svcnotifperiod`,
`hostnotifopt`, `svcnotifopt`, `hostnotifcmd`, `svcnotifcmd` ;
- le groupe de contacts, s'il est demandé.
Et pour l'ensemble du projet, `notifications/installer.sh`, qui dépose les scripts sur le
serveur.
## Rattacher un modèle à un périmètre
C'est ce qui referme la boucle. Un modèle d'hôte ou de service porte un champ **périmètre de
notification** ; renseigné, la génération ajoute au modèle :
```
HTPL;setparam;App-Facturation-custom;notifications_enabled;1
HTPL;setparam;App-Facturation-custom;notification_period;Heures-Ouvrees
HTPL;setparam;App-Facturation-custom;notification_options;d,u,r
HTPL;setparam;App-Facturation-custom;notification_interval;15
HTPL;setcontactgroup;App-Facturation-custom;CG-Facturation
```
Le modèle de service reçoit le même traitement, avec ses propres états déclencheurs — un
service en alerte et un hôte indisponible ne se notifient pas selon les mêmes règles.
Conséquence pratique : un hôte qui hérite de `App-Facturation-custom` arrive dans Centreon
avec sa chaîne de notification complète. Rien à reprendre à la main dans l'interface.
## Installation
Les scripts ne s'installent pas tout seuls — comme le CLAPI, Enclume les écrit et vous les
jouez, après relecture :
```bash
cd notifications
./installer.sh # vérifie la syntaxe PHP, puis dépose dans le répertoire cible
```
Le script d'installation contrôle chaque fichier avec `php -l` avant de le copier, et
l'installe en `0750` pour l'utilisateur du moteur de supervision.
Un agent de transport de courrier doit être en place sur la machine : le script utilise la
fonction `mail()` de PHP, qui passe par `sendmail`. L'adresse d'expédition se règle par la
variable d'environnement `ENCLUME_EXPEDITEUR`, à défaut `centreon@<nom de la machine>`.
## Composer le corps du message
Le corps est une liste de **blocs**, dans l'ordre d'affichage. Quatre natures :
| Bloc | Ce qu'il affiche |
|---|---|
| Macro Centreon | la valeur d'une macro, `$NOTIFICATIONAUTHOR$`, `$SERVICEPERFDATA$`, ou une macro personnalisée `$_HOSTAPPLI$` |
| Lien cliquable | une macro contenant une URL, `$SERVICENOTESURL$` par exemple, rendue en lien |
| Texte fixe | une consigne qui ne dépend pas de l'événement, « Appeler le 3000 si non résolu en 30 minutes » |
| Sortie du contrôle | la sortie du plugin, mise en avant en police fixe |
Les blocs se définissent séparément pour l'hôte et pour le service. Tant qu'aucun n'est
défini, les blocs par défaut s'appliquent — et le bouton « Composer à partir des blocs par
défaut » les recopie pour servir de point de départ.
**Une macro vide à l'exécution ne produit aucune ligne.** Un message d'acquittement affichera
donc l'auteur et son commentaire ; une notification de problème, où ces macros sont vides,
n'affichera pas de lignes creuses.
### Les macros personnalisées
C'est le vrai gain par rapport à un message figé. `$_HOSTAPPLI$` ou `$_HOSTRESPONSABLE$`,
définies comme macros sur l'hôte, produisent un message qui nomme *l'application concernée*
et non celle du périmètre entier. L'éditeur propose une quarantaine de macros standard en
suggestion, et accepte toute macro saisie à la main.
## Voir le message avant de le déployer
Dans l'éditeur, un périmètre propose **Aperçu du message, service** et **Aperçu du message,
hôte**. Le message s'affiche tel qu'il partira, avec un incident d'exemple : sujet,
destinataire, mise en forme complète, plus la commande Centreon correspondante.
L'aperçu et le script PHP partagent le même gabarit HTML — celui-ci est écrit une seule fois
et embarqué dans le script généré. Ce qui est montré est donc ce qui sera envoyé, et un test
vérifie que les deux ne peuvent pas diverger.
## Le message produit
Un message HTML avec un bandeau coloré selon l'état — vert rétabli, orange alerte, rouge
critique —, un tableau des informations de l'événement, la sortie du plugin en police fixe,
les champs métier du périmètre, et un lien vers la procédure de reprise quand elle est
renseignée.
Toutes les valeurs passent par `htmlspecialchars` : la sortie d'un plugin peut contenir
n'importe quoi, y compris des caractères qui casseraient la mise en page.
## Ce qu'Enclume ne fait pas
**Créer les contacts.** Ils doivent exister sur le central, avec leur adresse de courriel.
Enclume règle leurs paramètres de notification, il ne les invente pas.
**Envoyer le message.** Le site n'exécute rien, ici comme ailleurs.
**Gérer les escalades.** Elles ne sont pas exposées par CLAPI et restent à définir dans
l'interface de Centreon.
+167
View File
@@ -0,0 +1,167 @@
"""Connexion optionnelle par OpenID Connect.
Le site reste entierement utilisable sans compte : se connecter n'ajoute que
l'enregistrement de projets cote serveur et la soumission de packs.
Un seul fournisseur est declare, Authentik, qui federe lui-meme GitHub, Google
ou tout autre fournisseur social. L'application n'a donc jamais a connaitre les
identifiants de ces services, ni a etre redeployee quand on en ajoute un.
"""
from __future__ import annotations
import functools
from collections.abc import Callable
from typing import Any
from authlib.integrations.flask_client import OAuth
from flask import Blueprint, current_app, jsonify, redirect, request, session, url_for
from .config import Config
from .db import Utilisateur, db, maintenant
oauth = OAuth()
bp = Blueprint("auth", __name__)
def init_app(app) -> None:
oauth.init_app(app)
if not Config.oidc_actif():
return
oauth.register(
name="fournisseur",
client_id=Config.OIDC_CLIENT_ID,
client_secret=Config.OIDC_CLIENT_SECRET,
server_metadata_url=Config.OIDC_METADATA,
client_kwargs={"scope": Config.OIDC_SCOPES},
)
app.register_blueprint(bp)
# --------------------------------------------------------------------------- #
# Etat de la session
# --------------------------------------------------------------------------- #
def utilisateur_courant() -> Utilisateur | None:
identifiant = session.get("utilisateur_id")
if not identifiant or not Config.base_active():
return None
return db.session.get(Utilisateur, identifiant)
def est_administrateur(utilisateur: Utilisateur | None = None) -> bool:
utilisateur = utilisateur or utilisateur_courant()
return bool(utilisateur and utilisateur.administrateur)
def connexion_requise(vue: Callable) -> Callable:
@functools.wraps(vue)
def enveloppe(*args: Any, **kwargs: Any):
if utilisateur_courant() is None:
return jsonify({"erreur": "connexion requise"}), 401
return vue(*args, **kwargs)
return enveloppe
def administration_requise(vue: Callable) -> Callable:
@functools.wraps(vue)
def enveloppe(*args: Any, **kwargs: Any):
utilisateur = utilisateur_courant()
if utilisateur is None:
return jsonify({"erreur": "connexion requise"}), 401
if not utilisateur.administrateur:
return jsonify({"erreur": "reserve a la moderation"}), 403
return vue(*args, **kwargs)
return enveloppe
# --------------------------------------------------------------------------- #
# Parcours de connexion
# --------------------------------------------------------------------------- #
def _destination_sure(brut: str | None) -> str:
"""N'accepte qu'un chemin interne : pas de redirection ouverte."""
if not brut or not brut.startswith("/") or brut.startswith("//"):
return "/"
return brut
def url_de_retour() -> str:
"""URI de redirection annoncee au fournisseur.
Elle doit correspondre au caractere pres a celle declaree cote Authentik.
ENCLUME_URL_PUBLIQUE fait autorite quand elle est definie ; sinon on la
deduit de la requete, ce qui suppose que les en-tetes du proxy sont
honores (voir ProxyFix dans webapp).
"""
chemin = url_for("auth.retour")
if Config.URL_PUBLIQUE:
return f"{Config.URL_PUBLIQUE}{chemin}"
return url_for("auth.retour", _external=True)
@bp.get("/connexion")
def connexion():
session["retour"] = _destination_sure(request.args.get("retour"))
return oauth.fournisseur.authorize_redirect(url_de_retour())
@bp.get("/connexion/retour")
def retour():
try:
jeton = oauth.fournisseur.authorize_access_token()
except Exception:
current_app.logger.warning("echec de l'echange du jeton OIDC")
return redirect("/?connexion=echec")
revendications = jeton.get("userinfo") or {}
if not revendications:
try:
revendications = oauth.fournisseur.userinfo(token=jeton)
except Exception:
revendications = {}
sujet = str(revendications.get("sub") or "").strip()
if not sujet:
return redirect("/?connexion=echec")
utilisateur = db.session.query(Utilisateur).filter_by(sujet=sujet).one_or_none()
if utilisateur is None:
utilisateur = Utilisateur(sujet=sujet)
db.session.add(utilisateur)
utilisateur.email = str(revendications.get("email") or "")[:320]
utilisateur.nom = str(
revendications.get("name") or revendications.get("preferred_username") or ""
)[:255]
utilisateur.administrateur = _est_admin(revendications)
utilisateur.vu_le = maintenant()
db.session.commit()
session.clear()
session["utilisateur_id"] = utilisateur.id
session.permanent = True
return redirect(_destination_sure(session.pop("retour", "/")))
def _est_admin(revendications: dict) -> bool:
"""Deux voies : appartenance a un groupe, ou liste explicite de comptes.
La seconde existe pour le premier demarrage, avant que le mapping de portee
"groups" ne soit configure cote Authentik.
"""
groupes = revendications.get("groups") or []
if isinstance(groupes, str):
groupes = [groupes]
if Config.ADMIN_GROUPE and Config.ADMIN_GROUPE in groupes:
return True
email = str(revendications.get("email") or "").lower()
return bool(email and email in Config.ADMIN_COMPTES)
@bp.post("/deconnexion")
def deconnexion():
session.clear()
return jsonify({"statut": "deconnecte"})
+30 -9
View File
@@ -16,10 +16,25 @@ from typing import Any
import yaml
# Les categories sont celles des connecteurs de supervision Centreon : un pack
# Enclume se range la ou l'utilisateur ira le chercher dans la documentation
# officielle. L'ordre est celui de l'affichage.
CATEGORIES = {
"system": "Systemes d'exploitation",
"hardware": "Materiel",
"application": "Applications",
"operating-system": "Systemes d'exploitation",
"network": "Reseau",
"hardware-server": "Serveurs",
"storage": "Stockage",
"database": "Bases de donnees",
"applications": "Applications",
"virtualization": "Virtualisation",
"protocol": "Protocoles",
"ups-pdu": "Onduleurs et PDU",
"printer": "Imprimantes",
"sensor": "Capteurs",
"cloud": "Cloud",
"toip-voip": "ToIP et VoIP",
"blockchain": "Blockchain",
"centreon": "Centreon",
}
@@ -31,7 +46,7 @@ class Macro:
is_password: bool = False
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> "Macro":
def from_dict(cls, raw: dict[str, Any]) -> Macro:
return cls(
name=str(raw["name"]).strip().upper(),
value="" if raw.get("value") is None else str(raw.get("value")),
@@ -53,7 +68,7 @@ class Service:
max_attempts: int | None = None
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> "Service":
def from_dict(cls, raw: dict[str, Any]) -> Service:
return cls(
name=str(raw["name"]).strip(),
alias=str(raw.get("alias") or raw["name"]).strip(),
@@ -77,7 +92,7 @@ class HostTemplate:
macros: list[Macro] = field(default_factory=list)
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> "HostTemplate":
def from_dict(cls, raw: dict[str, Any]) -> HostTemplate:
return cls(
name=str(raw["name"]).strip(),
alias=str(raw.get("alias") or raw["name"]).strip(),
@@ -98,6 +113,9 @@ class Pack:
status: str
host_template: HostTemplate
services: list[Service]
prerequis: dict[str, Any] = field(default_factory=dict)
notification: dict[str, Any] = field(default_factory=dict)
groupe_hote: dict[str, Any] = field(default_factory=dict)
source_file: str = ""
@property
@@ -120,16 +138,19 @@ class Pack:
return None
@classmethod
def from_dict(cls, raw: dict[str, Any], source_file: str = "") -> "Pack":
def from_dict(cls, raw: dict[str, Any], source_file: str = "") -> Pack:
return cls(
id=str(raw["id"]).strip(),
name=str(raw["name"]).strip(),
category=str(raw.get("category", "system")).strip(),
category=str(raw.get("category", "applications")).strip(),
description=str(raw.get("description", "")),
plugin=str(raw.get("plugin", "")),
status=str(raw.get("status", "to-verify")),
host_template=HostTemplate.from_dict(raw["host_template"]),
services=[Service.from_dict(s) for s in raw.get("services") or []],
prerequis=raw.get("prerequis") or {},
notification=raw.get("notification") or {},
groupe_hote=raw.get("groupe_hote") or {},
source_file=source_file,
)
@@ -153,7 +174,7 @@ class Catalog:
with open(path, encoding="utf-8") as handle:
raw = yaml.safe_load(handle)
pack = Pack.from_dict(raw, source_file=path)
except Exception as exc: # noqa: BLE001 - remonte tel quel a l'UI
except Exception as exc:
self.errors.append(f"{path} : {exc}")
continue
if pack.id in self.packs:
+12 -4
View File
@@ -25,14 +25,22 @@ def main(argv: list[str] | None = None) -> int:
parser.add_argument("--catalog", default=os.environ.get("ENCLUME_CATALOG", DEFAULT_CATALOG))
parser.add_argument("--list", action="store_true", help="liste les packs disponibles")
parser.add_argument("--pack", action="append", default=[], help="pack a importer (repetable)")
parser.add_argument("--tout", action="store_true", help="importer toutes les sondes, pas seulement celles par defaut")
parser.add_argument(
"--tout",
action="store_true",
help="importer toutes les sondes, pas seulement celles par defaut",
)
parser.add_argument("--projet", help="fichier de projet JSON exporte depuis le site")
parser.add_argument("--prefix", default="", help="prefixe applique aux objets crees")
parser.add_argument("--plugins-dir", default="/usr/lib/centreon/plugins")
parser.add_argument("--version-centreon", default="24.x")
parser.add_argument("--poller", default="Central")
parser.add_argument("--out", help="repertoire de sortie (defaut : stdout)")
parser.add_argument("--strict", action="store_true", help="code de retour non nul si le projet contient une erreur")
parser.add_argument(
"--strict",
action="store_true",
help="code de retour non nul si le projet contient une erreur",
)
args = parser.parse_args(argv)
catalog = Catalog(args.catalog)
@@ -93,5 +101,5 @@ def main(argv: list[str] | None = None) -> int:
if __name__ == "__main__":
try:
raise SystemExit(main())
except BrokenPipeError:
raise SystemExit(0)
except BrokenPipeError: # sortie tronquee par un pipe, ex. | head
raise SystemExit(0) from None
+148
View File
@@ -0,0 +1,148 @@
"""Configuration lue depuis l'environnement.
Toutes les fonctionnalites ajoutees aux chantiers 3 a 5 sont facultatives :
sans base de donnees, sans OIDC et sans jeton Gitea, l'application reste
exactement ce qu'elle etait — un editeur qui genere du CLAPI. C'est ce qui
permet a n'importe qui de l'auto-heberger en trois lignes.
"""
from __future__ import annotations
import os
import secrets
from urllib.parse import quote
def _bool(nom: str, defaut: bool = False) -> bool:
brut = os.environ.get(nom)
if brut is None:
return defaut
return brut.strip().lower() in {"1", "true", "oui", "yes", "on"}
def _url_publique() -> str:
"""Adresse publique du site, normalisee.
Une barre finale ou un protocole absent suffirait a faire diverger l'URI de
redirection de celle declaree chez le fournisseur.
"""
brut = os.environ.get("ENCLUME_URL_PUBLIQUE", "").strip().rstrip("/")
if not brut:
return ""
if not brut.startswith(("http://", "https://")):
brut = f"https://{brut}"
return brut
def _url_base() -> str:
"""Assemble l'URL PostgreSQL a partir des variables separees."""
hote = os.environ.get("ENCLUME_DB_HOTE", "")
if not hote:
return ""
utilisateur = quote(os.environ.get("ENCLUME_DB_UTILISATEUR", "enclume"), safe="")
motdepasse = quote(os.environ.get("ENCLUME_DB_MOTDEPASSE", ""), safe="")
port = os.environ.get("ENCLUME_DB_PORT", "5432")
base = os.environ.get("ENCLUME_DB_NOM", "enclume")
return f"postgresql+psycopg://{utilisateur}:{motdepasse}@{hote}:{port}/{base}"
def _int(nom: str, defaut: int) -> int:
try:
return int(os.environ.get(nom, defaut))
except (TypeError, ValueError):
return defaut
class Config:
# --- Identite du service ------------------------------------------------
VERSION = os.environ.get("ENCLUME_VERSION", "dev")
COMMIT = os.environ.get("ENCLUME_COMMIT", "inconnu")
URL_PUBLIQUE = _url_publique()
DEPOT = os.environ.get(
"ENCLUME_DEPOT", "https://gitea.tips-of-mine.com/Tips-Of-Mine/Enclume"
).rstrip("/")
# --- Mentions legales ---------------------------------------------------
# Sans ces valeurs, la page affiche ce qui manque plutot qu'une page vide.
EDITEUR = os.environ.get("ENCLUME_EDITEUR", "")
CONTACT = os.environ.get("ENCLUME_CONTACT", "")
HEBERGEUR = os.environ.get("ENCLUME_HEBERGEUR", "")
# --- Sessions -----------------------------------------------------------
# Sans cle fournie, on en tire une au demarrage : les sessions ne survivent
# pas a un redemarrage, ce qui est acceptable en developpement et bruyant
# en production, donc visible.
SECRET_KEY = os.environ.get("ENCLUME_SECRET_KEY") or secrets.token_hex(32)
SECRET_KEY_FOURNIE = bool(os.environ.get("ENCLUME_SECRET_KEY"))
SESSION_COOKIE_NAME = "enclume"
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"
SESSION_COOKIE_SECURE = _bool("ENCLUME_COOKIE_SECURE", True)
PERMANENT_SESSION_LIFETIME = _int("ENCLUME_SESSION_JOURS", 30) * 86400
# --- Base de donnees ----------------------------------------------------
# L'URL peut etre fournie telle quelle, ou assemblee a partir des elements.
# La seconde voie est preferable : un mot de passe contenant @ : / ? #
# casserait une URL ecrite a la main, alors qu'ici il est encode.
SQLALCHEMY_DATABASE_URI = os.environ.get("ENCLUME_DATABASE_URL", "") or _url_base()
SQLALCHEMY_ENGINE_OPTIONS = {"pool_pre_ping": True, "pool_recycle": 1800}
# --- Partage ------------------------------------------------------------
PARTAGE_JOURS = _int("ENCLUME_PARTAGE_JOURS", 90)
PROJETS_PAR_COMPTE = _int("ENCLUME_PROJETS_PAR_COMPTE", 50)
# --- Authentification OIDC (Authentik) ----------------------------------
OIDC_NOM = os.environ.get("ENCLUME_OIDC_NOM", "Authentik")
OIDC_METADATA = os.environ.get("ENCLUME_OIDC_METADATA", "")
OIDC_CLIENT_ID = os.environ.get("ENCLUME_OIDC_CLIENT_ID", "")
OIDC_CLIENT_SECRET = os.environ.get("ENCLUME_OIDC_CLIENT_SECRET", "")
OIDC_SCOPES = os.environ.get("ENCLUME_OIDC_SCOPES", "openid email profile")
# Le groupe qui donne acces a la moderation. Necessite que le fournisseur
# place la revendication "groups" dans le jeton (mapping de portee dedie
# cote Authentik).
# Les comptes sont-ils ouverts au public, ou reserves a l'equipe ?
# Tant que le fournisseur d'identite n'accepte pas les inscriptions, annoncer
# une connexion ouverte enverrait les visiteurs dans une impasse.
INSCRIPTION_OUVERTE = _bool("ENCLUME_INSCRIPTION_OUVERTE", False)
ADMIN_GROUPE = os.environ.get("ENCLUME_ADMIN_GROUPE", "enclume-admins")
ADMIN_COMPTES = [
c.strip().lower()
for c in os.environ.get("ENCLUME_ADMIN_COMPTES", "").split(",")
if c.strip()
]
# --- Depot du catalogue, pour les soumissions ---------------------------
GITEA_URL = os.environ.get("ENCLUME_GITEA_URL", "").rstrip("/")
GITEA_TOKEN = os.environ.get("ENCLUME_GITEA_TOKEN", "")
GITEA_PROPRIETAIRE = os.environ.get("ENCLUME_GITEA_PROPRIETAIRE", "")
GITEA_DEPOT = os.environ.get("ENCLUME_GITEA_DEPOT", "")
GITEA_BRANCHE = os.environ.get("ENCLUME_GITEA_BRANCHE", "main")
GITEA_SOUS_DOSSIER = os.environ.get("ENCLUME_GITEA_SOUS_DOSSIER", "catalog")
# --- Limites ------------------------------------------------------------
TAILLE_MAX_PROJET = _int("ENCLUME_TAILLE_MAX_PROJET", 2 * 1024 * 1024)
TAILLE_MAX_PACK = _int("ENCLUME_TAILLE_MAX_PACK", 256 * 1024)
SOUMISSIONS_PAR_JOUR = _int("ENCLUME_SOUMISSIONS_PAR_JOUR", 10)
@classmethod
def base_active(cls) -> bool:
return bool(cls.SQLALCHEMY_DATABASE_URI)
@classmethod
def oidc_actif(cls) -> bool:
return bool(cls.OIDC_METADATA and cls.OIDC_CLIENT_ID and cls.OIDC_CLIENT_SECRET)
@classmethod
def gitea_actif(cls) -> bool:
return bool(cls.GITEA_URL and cls.GITEA_TOKEN and cls.GITEA_PROPRIETAIRE and cls.GITEA_DEPOT)
@classmethod
def etat(cls) -> dict[str, bool]:
"""Ce que le site sait faire, tel qu'annonce a l'interface."""
return {
"comptes": cls.base_active() and cls.oidc_actif(),
"partage": cls.base_active(),
"projets_enregistres": cls.base_active() and cls.oidc_actif(),
"soumissions": cls.base_active() and cls.oidc_actif(),
"publication_gitea": cls.gitea_actif(),
}
+174
View File
@@ -0,0 +1,174 @@
"""Persistance : comptes, projets enregistres, partages, soumissions de packs.
Toutes les tables sont facultatives : sans ENCLUME_DATABASE_URL, rien de tout
cela n'est instancie et l'application fonctionne en mode sans etat.
Regle de migration : on ajoute, on ne retire jamais dans la meme version que le
code qui cesse d'utiliser une colonne. La suppression arrive une version plus
tard, quand le retour arriere n'est plus envisage.
"""
from __future__ import annotations
import secrets
from datetime import UTC, datetime, timedelta
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import (
Boolean,
DateTime,
ForeignKey,
Index,
Integer,
String,
Text,
func,
)
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
db = SQLAlchemy(model_class=Base)
def maintenant() -> datetime:
return datetime.now(UTC)
def _identifiant_court() -> str:
"""12 caracteres d'alphabet URL, soit 72 bits : non enumerable."""
return secrets.token_urlsafe(9)
class Utilisateur(db.Model):
__tablename__ = "utilisateurs"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
# Identifiant stable du fournisseur OIDC (revendication "sub").
sujet: Mapped[str] = mapped_column(String(255), unique=True, nullable=False)
email: Mapped[str] = mapped_column(String(320), default="")
nom: Mapped[str] = mapped_column(String(255), default="")
administrateur: Mapped[bool] = mapped_column(Boolean, default=False)
cree_le: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=maintenant)
vu_le: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=maintenant)
projets: Mapped[list[Projet]] = relationship(back_populates="proprietaire", cascade="all, delete-orphan")
@property
def affichage(self) -> str:
return self.nom or self.email or f"compte {self.id}"
class Projet(db.Model):
__tablename__ = "projets"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
utilisateur_id: Mapped[int] = mapped_column(ForeignKey("utilisateurs.id"), nullable=False)
nom: Mapped[str] = mapped_column(String(255), default="Projet sans nom")
contenu: Mapped[str] = mapped_column(Text, nullable=False)
cree_le: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=maintenant)
maj_le: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=maintenant, onupdate=maintenant)
proprietaire: Mapped[Utilisateur] = relationship(back_populates="projets")
__table_args__ = (Index("ix_projets_utilisateur", "utilisateur_id"),)
def resume(self) -> dict:
return {
"id": self.id,
"nom": self.nom,
"maj_le": self.maj_le.isoformat() if self.maj_le else None,
}
class Partage(db.Model):
__tablename__ = "partages"
id: Mapped[str] = mapped_column(String(32), primary_key=True, default=_identifiant_court)
contenu: Mapped[str] = mapped_column(Text, nullable=False)
nom: Mapped[str] = mapped_column(String(255), default="")
utilisateur_id: Mapped[int | None] = mapped_column(ForeignKey("utilisateurs.id"), nullable=True)
cree_le: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=maintenant)
expire_le: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
vues: Mapped[int] = mapped_column(Integer, default=0)
@classmethod
def creer(cls, contenu: str, nom: str, jours: int, utilisateur_id: int | None = None) -> Partage:
return cls(
contenu=contenu,
nom=nom[:255],
utilisateur_id=utilisateur_id,
expire_le=maintenant() + timedelta(days=jours),
)
@property
def expire(self) -> bool:
limite = self.expire_le
if limite.tzinfo is None: # SQLite rend des datetimes naifs
limite = limite.replace(tzinfo=UTC)
return limite < maintenant()
class Soumission(db.Model):
__tablename__ = "soumissions"
EN_ATTENTE = "en_attente"
PUBLIEE = "publiee"
REFUSEE = "refusee"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
utilisateur_id: Mapped[int] = mapped_column(ForeignKey("utilisateurs.id"), nullable=False)
pack_id: Mapped[str] = mapped_column(String(64), nullable=False)
categorie: Mapped[str] = mapped_column(String(32), nullable=False)
nom: Mapped[str] = mapped_column(String(255), default="")
contenu: Mapped[str] = mapped_column(Text, nullable=False) # le YAML soumis
message: Mapped[str] = mapped_column(Text, default="") # mot de l'auteur
statut: Mapped[str] = mapped_column(String(16), default=EN_ATTENTE)
reponse: Mapped[str] = mapped_column(Text, default="") # motif du refus
url_pr: Mapped[str] = mapped_column(String(512), default="")
cree_le: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=maintenant)
traite_le: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
auteur: Mapped[Utilisateur] = relationship()
__table_args__ = (Index("ix_soumissions_statut", "statut"),)
def resume(self, avec_auteur: bool = False) -> dict:
donnees = {
"id": self.id,
"pack_id": self.pack_id,
"categorie": self.categorie,
"nom": self.nom,
"statut": self.statut,
"message": self.message,
"reponse": self.reponse,
"url_pr": self.url_pr,
"cree_le": self.cree_le.isoformat() if self.cree_le else None,
}
if avec_auteur and self.auteur is not None:
donnees["auteur"] = self.auteur.affichage
return donnees
def compter_soumissions_du_jour(utilisateur_id: int) -> int:
depuis = maintenant() - timedelta(days=1)
return (
db.session.query(func.count(Soumission.id))
.filter(Soumission.utilisateur_id == utilisateur_id, Soumission.cree_le >= depuis)
.scalar()
or 0
)
def purger_partages_expires() -> int:
"""Menage opportuniste : appele a la creation d'un partage."""
supprimes = (
db.session.query(Partage)
.filter(Partage.expire_le < maintenant())
.delete(synchronize_session=False)
)
db.session.commit()
return supprimes or 0
+162 -6
View File
@@ -7,10 +7,11 @@ livres a l'utilisateur ne sont que des rendus differents de cette liste.
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import datetime, timezone
from datetime import UTC, datetime
from typing import Any
from .model import Macro, Project, validate
from .model import JOURS, Macro, Project, validate
from .notifications import commande_notification, nom_script, rendre_installation, rendre_script
CLAPI_BIN = "/usr/share/centreon/bin/centreon"
@@ -46,6 +47,9 @@ class Plan:
"modeles de service": len(self.project.service_templates),
"modeles d'hote": len(self.project.host_templates),
"hotes": len(self.project.hosts),
"groupes d'hote": len(self.project.groupes_hotes),
"calendriers": len(self.project.calendriers),
"perimetres de notification": len(self.project.perimetres),
"operations": len([o for o in self.ops if o.obj != "#"]),
}
@@ -70,6 +74,7 @@ def build_plan(project: Project) -> Plan:
own_commands = {c.name for c in project.commands}
own_htpl = {h.name for h in project.host_templates}
own_tp = {c.name for c in project.calendriers if c.creer}
def ref_command(name: str) -> str:
"""Un objet du projet est prefixe ; un objet deja present sur le central ne l'est pas."""
@@ -79,6 +84,9 @@ def build_plan(project: Project) -> Plan:
return full(name) if name in own_htpl else name
del_cmd: list[Op] = []
del_tp: list[Op] = []
del_cg: list[Op] = []
del_hg: list[Op] = []
del_stpl: list[Op] = []
del_htpl: list[Op] = []
del_host: list[Op] = []
@@ -135,12 +143,101 @@ def build_plan(project: Project) -> Plan:
plan.ops.append(Op("HTPL", "setmacro", _macro_values(full(htpl.name), macro, fields)))
del_htpl.append(Op("HTPL", "DEL", [full(htpl.name)]))
# --- Notifications : calendriers, commandes, contacts -------------------
if any(c.creer for c in project.calendriers):
plan.ops.append(Op("#", "#", comment="Calendriers de notification"))
for calendrier in project.calendriers:
if not calendrier.creer:
# Livre par Centreon : on s'y refere, on ne le recree pas.
continue
plan.ops.append(Op("TP", "ADD", [full(calendrier.name), calendrier.alias or calendrier.name]))
for jour in JOURS:
plage = calendrier.jours.get(jour)
if plage:
plan.ops.append(Op("TP", "setparam", [full(calendrier.name), jour, plage]))
del_tp.append(Op("TP", "DEL", [full(calendrier.name)]))
if project.perimetres:
plan.ops.append(Op("#", "#", comment="Perimetres de notification"))
for perimetre in project.perimetres:
for pour, suffixe in (("host", "Host"), ("service", "Service")):
nom = full(f"{perimetre.name}-Notify-{suffixe}")
plan.ops.append(
Op("CMD", "ADD", [nom, "notif", commande_notification(project, perimetre, pour)])
)
del_cmd.append(Op("CMD", "DEL", [nom]))
if perimetre.groupe:
plan.ops.append(Op("CG", "ADD", [full(perimetre.groupe), perimetre.name]))
if perimetre.contacts:
plan.ops.append(
Op("CG", "setcontact", [full(perimetre.groupe), "|".join(perimetre.contacts)])
)
del_cg.append(Op("CG", "DEL", [full(perimetre.groupe)]))
calendrier = full(perimetre.calendrier) if perimetre.calendrier in own_tp else perimetre.calendrier
for contact in perimetre.contacts:
for parametre, valeur in (
("hostnotifperiod", calendrier),
("svcnotifperiod", calendrier),
("hostnotifopt", perimetre.options_hote),
("svcnotifopt", perimetre.options_service),
("hostnotifcmd", full(f"{perimetre.name}-Notify-Host")),
("svcnotifcmd", full(f"{perimetre.name}-Notify-Service")),
):
plan.ops.append(Op("CONTACT", "setparam", [contact, parametre, valeur]))
par_nom = {p.name: p for p in project.perimetres}
def cabler_notification(objet_clapi: str, nom: str, perimetre, pour_hote: bool) -> None:
"""Rattache un modele a son perimetre : calendrier, etats, destinataires.
Sans cela, un modele applicatif serait cree sans savoir qui prevenir ni
quand — et il faudrait le reprendre a la main dans l'interface.
"""
calendrier = (
full(perimetre.calendrier) if perimetre.calendrier in own_tp else perimetre.calendrier
)
options = perimetre.options_hote if pour_hote else perimetre.options_service
plan.ops.append(Op(objet_clapi, "setparam", [nom, "notifications_enabled", "1"]))
if calendrier:
plan.ops.append(Op(objet_clapi, "setparam", [nom, "notification_period", calendrier]))
if options:
plan.ops.append(Op(objet_clapi, "setparam", [nom, "notification_options", options]))
if perimetre.intervalle:
plan.ops.append(
Op(objet_clapi, "setparam", [nom, "notification_interval", str(perimetre.intervalle)])
)
if perimetre.groupe:
plan.ops.append(Op(objet_clapi, "setcontactgroup", [nom, full(perimetre.groupe)]))
rattachements = [
("HTPL", full(h.name), par_nom.get(h.perimetre), True)
for h in project.host_templates
if h.perimetre and h.perimetre in par_nom
] + [
("STPL", full(s.name), par_nom.get(s.perimetre), False)
for s in project.service_templates
if s.perimetre and s.perimetre in par_nom
]
if rattachements:
plan.ops.append(Op("#", "#", comment="Rattachement des modeles a leur perimetre"))
for objet_clapi, nom, perimetre, pour_hote in rattachements:
cabler_notification(objet_clapi, nom, perimetre, pour_hote)
links = [(s, h) for s in project.service_templates for h in s.host_templates]
if links:
plan.ops.append(Op("#", "#", comment="Rattachement des modeles de service aux modeles d'hote"))
for stpl, htpl_name in links:
plan.ops.append(Op("STPL", "addhosttemplate", [full(stpl.name), ref_htpl(htpl_name)]))
if project.groupes_hotes:
plan.ops.append(Op("#", "#", comment="Groupes d'hotes"))
own_hg = {g.name for g in project.groupes_hotes}
for groupe in project.groupes_hotes:
plan.ops.append(Op("HG", "ADD", [full(groupe.name), groupe.alias or groupe.name]))
del_hg.append(Op("HG", "DEL", [full(groupe.name)]))
if project.hosts:
plan.ops.append(Op("#", "#", comment="Hotes"))
for host in project.hosts:
@@ -154,16 +251,23 @@ def build_plan(project: Project) -> Plan:
host.address,
"|".join(ref_htpl(t) for t in host.templates),
host.poller or project.poller,
host.hostgroups,
"|".join(full(h) if h in own_hg else h for h in host.hostgroups),
],
)
)
for param, valeur in (
("check_command", ref_command(host.check_command) if host.check_command else ""),
("check_command_arguments", host.check_command_args),
("timezone", host.timezone),
):
if valeur:
plan.ops.append(Op("HOST", "setparam", [host.name, param, valeur]))
for macro in host.macros:
plan.ops.append(Op("HOST", "setmacro", _macro_values(host.name, macro, fields)))
plan.ops.append(Op("HOST", "applytpl", [host.name]))
del_host.append(Op("HOST", "DEL", [host.name]))
plan.rollback_ops = [*del_host, *del_stpl, *del_htpl, *del_cmd]
plan.rollback_ops = [*del_host, *del_hg, *del_stpl, *del_htpl, *del_cg, *del_cmd, *del_tp]
return plan
@@ -172,7 +276,7 @@ def build_plan(project: Project) -> Plan:
# --------------------------------------------------------------------------- #
def _header(title: str, plan: Plan) -> list[str]:
stamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
stamp = datetime.now(UTC).strftime("%Y-%m-%d %H:%M UTC")
summary = ", ".join(f"{v} {k}" for k, v in plan.summary.items() if v)
return [
f"# {title} - {plan.project.name}",
@@ -244,14 +348,66 @@ def render_shell(plan: Plan, ops: list[Op], title: str, apply_config: bool) -> s
return "\n".join(lines)
def render_prerequis(plan: Plan) -> str:
"""Fichier separe : ce qui s'installe sur le collecteur, jamais du CLAPI."""
prerequis = plan.project.prerequis
lignes = [
"#!/usr/bin/env bash",
"#",
f"# Prerequis des sondes - {plan.project.name}",
"# Genere par Enclume. A RELIRE AVANT EXECUTION.",
"#",
"# Ce fichier n'est pas du CLAPI : il s'execute sur le collecteur qui",
"# porte les plugins, pas sur le serveur central. Les commandes sont",
"# commentees par distribution ; decommentez celle qui vous concerne.",
"#",
"set -euo pipefail",
"",
]
if prerequis.paquets_debian:
lignes += [
"# Debian et Ubuntu",
"# apt-get update",
"# apt-get install -y " + " ".join(prerequis.paquets_debian),
"",
]
if prerequis.paquets_rhel:
lignes += [
"# RHEL, Alma, Rocky",
"# dnf install -y " + " ".join(prerequis.paquets_rhel),
"",
]
if prerequis.notes:
lignes += ["# Notes de l'auteur du pack :"]
lignes += [f"# {ligne}" for ligne in prerequis.notes.splitlines()]
lignes += [""]
if prerequis.verifications:
lignes += ["# Verifications, sans effet de bord :"]
for verification in prerequis.verifications:
lignes.append(verification)
lignes.append("")
lignes += ['echo "Prerequis passes en revue."', ""]
return "\n".join(lignes)
def render_bundle(plan: Plan) -> dict[str, str]:
apply_config = bool(plan.project.apply_config)
return {
fichiers = {
"deploy.clapi": render_import(plan, plan.ops, "Deploiement CLAPI"),
"deploy.sh": render_shell(plan, plan.ops, "Deploiement CLAPI", apply_config),
"rollback.clapi": render_import(plan, plan.rollback_ops, "Suppression des objets"),
"rollback.sh": render_shell(plan, plan.rollback_ops, "Suppression des objets", apply_config),
}
if not plan.project.prerequis.vide:
fichiers["prerequis.sh"] = render_prerequis(plan)
for perimetre in plan.project.perimetres:
fichiers[f"notifications/{nom_script(perimetre)}"] = rendre_script(plan.project, perimetre)
if plan.project.perimetres:
fichiers["notifications/installer.sh"] = rendre_installation(plan.project)
return fichiers
def generate(raw_project: dict[str, Any]) -> dict[str, Any]:
+118
View File
@@ -0,0 +1,118 @@
"""Publication d'un pack accepte, sous forme de pull request Gitea.
Choix volontaire : la moderation n'ecrit jamais directement sur la branche
principale. Elle ouvre une demande, que tu relis dans Gitea avant de fusionner.
Git reste la source de verite du catalogue, et une acceptation par erreur dans
l'interface reste rattrapable en un clic.
"""
from __future__ import annotations
import base64
import json
import re
import urllib.error
import urllib.request
from .config import Config
TIMEOUT = 15
class ErreurGitea(RuntimeError):
pass
def _appel(methode: str, chemin: str, corps: dict | None = None) -> dict:
url = f"{Config.GITEA_URL}/api/v1{chemin}"
donnees = json.dumps(corps).encode("utf-8") if corps is not None else None
requete = urllib.request.Request(url, data=donnees, method=methode)
requete.add_header("Authorization", f"token {Config.GITEA_TOKEN}")
requete.add_header("Content-Type", "application/json")
requete.add_header("Accept", "application/json")
# Sans agent utilisateur explicite, urllib s'annonce comme "Python-urllib",
# que les protections applicatives placees devant Gitea rejettent souvent.
requete.add_header("User-Agent", f"Enclume/{Config.VERSION} (+{Config.URL_PUBLIQUE})")
try:
with urllib.request.urlopen(requete, timeout=TIMEOUT) as reponse:
charge = reponse.read().decode("utf-8")
return json.loads(charge) if charge else {}
except urllib.error.HTTPError as erreur:
detail = erreur.read().decode("utf-8", "replace")[:300].strip()
if erreur.code == 422 and "already exists" in detail.lower():
raise ErreurGitea(
"Un fichier portant cet identifiant existe deja dans le depot du catalogue. "
"Refuser la soumission, ou demander a l'auteur un identifiant distinct."
) from erreur
if erreur.code == 409:
raise ErreurGitea(
"Une branche portant ce nom existe deja dans le depot. "
"La supprimer dans Gitea, puis relancer la publication."
) from erreur
if "error code: 1010" in detail or "cloudflare" in detail.lower():
raise ErreurGitea(
f"HTTP {erreur.code} : la requete a ete bloquee avant d'atteindre Gitea, "
"par la protection placee devant lui. Faire pointer ENCLUME_GITEA_URL vers "
"l'adresse interne du serveur, ou ajouter une entree extra_hosts."
) from erreur
raise ErreurGitea(f"{methode} {chemin} : HTTP {erreur.code} — {detail}") from erreur
except urllib.error.URLError as erreur:
raise ErreurGitea(f"{methode} {chemin} : {erreur.reason}") from erreur
def _nom_de_branche(pack_id: str, soumission_id: int) -> str:
base = re.sub(r"[^a-z0-9-]+", "-", pack_id.lower()).strip("-") or "pack"
return f"pack/{base}-{soumission_id}"
def ouvrir_demande(soumission, auteur: str) -> str:
"""Cree la branche, y depose le pack, ouvre la pull request. Rend son URL."""
if not Config.gitea_actif():
raise ErreurGitea("publication Gitea non configuree")
proprietaire = Config.GITEA_PROPRIETAIRE
depot = Config.GITEA_DEPOT
branche = _nom_de_branche(soumission.pack_id, soumission.id)
chemin = f"{Config.GITEA_SOUS_DOSSIER}/{soumission.categorie}/{soumission.pack_id}.yml"
# Un seul appel cree la branche et le fichier : new_branch part de branch.
_appel(
"POST",
f"/repos/{proprietaire}/{depot}/contents/{chemin}",
{
"content": base64.b64encode(soumission.contenu.encode("utf-8")).decode("ascii"),
"message": f"Ajout du pack {soumission.pack_id} ({soumission.categorie})",
"branch": Config.GITEA_BRANCHE,
"new_branch": branche,
},
)
corps = [
f"Pack **{soumission.nom or soumission.pack_id}** propose depuis Enclume.",
"",
f"- identifiant : `{soumission.pack_id}`",
f"- categorie : `{soumission.categorie}`",
f"- auteur : {auteur}",
f"- soumission : #{soumission.id}",
]
if soumission.message:
corps += ["", "Message de l'auteur :", "", f"> {soumission.message.strip()}"]
corps += [
"",
"---",
"Contribution externe : relire la ligne de commande, les macros et les "
"eventuels prerequis avant de fusionner.",
]
demande = _appel(
"POST",
f"/repos/{proprietaire}/{depot}/pulls",
{
"head": branche,
"base": Config.GITEA_BRANCHE,
"title": f"Pack {soumission.pack_id}",
"body": "\n".join(corps),
},
)
return str(demande.get("html_url") or "")
+349 -16
View File
@@ -10,21 +10,43 @@ qu'on exporte, ce qu'on partage et ce que la CI rejoue.
from __future__ import annotations
import re
from dataclasses import asdict, dataclass, field
from typing import Any
SCHEMA_VERSION = 1
# Versions de Centreon proposees dans l'editeur et ce qu'elles impliquent.
# Centreon nomme ses versions par annee et saison de livraison : XX.04 au
# printemps, XX.10 a l'automne. Les versions des annees paires sont supportees
# trois ans (LTS) depuis la 24.10, celles des annees impaires dix-huit mois.
CENTREON_VERSIONS: dict[str, dict[str, Any]] = {
"24.x": {"label": "Centreon 24.x", "macro_fields": 5},
"23.x": {"label": "Centreon 23.x", "macro_fields": 5},
"22.x": {"label": "Centreon 22.x", "macro_fields": 5},
"21.x": {"label": "Centreon 21.x", "macro_fields": 5},
"25.10": {"label": "Centreon 25.10", "macro_fields": 5},
"25.04": {"label": "Centreon 25.04", "macro_fields": 5},
"24.10": {"label": "Centreon 24.10 (LTS)", "macro_fields": 5},
"24.04": {"label": "Centreon 24.04", "macro_fields": 5},
"23.10": {"label": "Centreon 23.10", "macro_fields": 5},
"23.04": {"label": "Centreon 23.04", "macro_fields": 5},
"22.10": {"label": "Centreon 22.10", "macro_fields": 5},
"22.04": {"label": "Centreon 22.04", "macro_fields": 5},
"21.10": {"label": "Centreon 21.10", "macro_fields": 5},
"21.04": {"label": "Centreon 21.04", "macro_fields": 5},
"20.10": {"label": "Centreon 20.10", "macro_fields": 5},
"20.04": {"label": "Centreon 20.04", "macro_fields": 5},
"legacy": {"label": "Centreon anterieur a 20.04", "macro_fields": 3},
}
VERSION_PAR_DEFAUT = "25.10"
# Les premieres versions d'Enclume proposaient des familles ("24.x") plutot que
# des versions reelles. Les projets enregistres a cette epoque restent lisibles.
VERSIONS_HISTORIQUES = {
"24.x": "24.10",
"23.x": "23.10",
"22.x": "22.10",
"21.x": "21.10",
}
COMMAND_TYPES = {"check": "Controle", "notif": "Notification", "misc": "Divers", "discovery": "Decouverte"}
FORBIDDEN = ";"
@@ -34,6 +56,15 @@ def _clean(value: Any) -> str:
return "" if value is None else str(value).strip()
def _liste(valeur: Any) -> list[str]:
"""Accepte une liste, ou une chaine separee par | ou par virgule."""
if isinstance(valeur, list):
return [_clean(v) for v in valeur if _clean(v)]
if not _clean(valeur):
return []
return [morceau.strip() for morceau in re.split(r"[|,]", str(valeur)) if morceau.strip()]
@dataclass
class Macro:
name: str = ""
@@ -42,7 +73,7 @@ class Macro:
is_password: bool = False
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> "Macro":
def from_dict(cls, raw: dict[str, Any]) -> Macro:
return cls(
name=_clean(raw.get("name")).upper(),
value="" if raw.get("value") is None else str(raw.get("value")),
@@ -59,7 +90,7 @@ class Command:
comment: str = ""
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> "Command":
def from_dict(cls, raw: dict[str, Any]) -> Command:
return cls(
name=_clean(raw.get("name")),
type=_clean(raw.get("type")) or "check",
@@ -81,10 +112,11 @@ class ServiceTemplate:
active_checks: int = 1
passive_checks: int = 0
host_templates: list[str] = field(default_factory=list)
perimetre: str = ""
macros: list[Macro] = field(default_factory=list)
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> "ServiceTemplate":
def from_dict(cls, raw: dict[str, Any]) -> ServiceTemplate:
def as_int(key: str, default: int) -> int:
try:
return int(raw.get(key, default))
@@ -103,6 +135,7 @@ class ServiceTemplate:
active_checks=as_int("active_checks", 1),
passive_checks=as_int("passive_checks", 0),
host_templates=[_clean(h) for h in raw.get("host_templates") or [] if _clean(h)],
perimetre=_clean(raw.get("perimetre")),
macros=[Macro.from_dict(m) for m in raw.get("macros") or []],
)
@@ -117,10 +150,11 @@ class HostTemplate:
snmp_version: str = ""
snmp_community: str = ""
timezone: str = ""
perimetre: str = ""
macros: list[Macro] = field(default_factory=list)
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> "HostTemplate":
def from_dict(cls, raw: dict[str, Any]) -> HostTemplate:
return cls(
name=_clean(raw.get("name")),
alias=_clean(raw.get("alias")),
@@ -130,10 +164,27 @@ class HostTemplate:
snmp_version=_clean(raw.get("snmp_version")),
snmp_community=_clean(raw.get("snmp_community")),
timezone=_clean(raw.get("timezone")),
perimetre=_clean(raw.get("perimetre")),
macros=[Macro.from_dict(m) for m in raw.get("macros") or []],
)
@dataclass
class GroupeHote:
"""Groupe d'hotes Centreon, objet HG.
Sert au classement dans l'interface, aux filtres et aux droits : un hote
sans groupe est difficile a retrouver des que le parc grandit.
"""
name: str = ""
alias: str = ""
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> GroupeHote:
return cls(name=_clean(raw.get("name")), alias=_clean(raw.get("alias")))
@dataclass
class Host:
name: str = ""
@@ -141,26 +192,218 @@ class Host:
address: str = ""
templates: list[str] = field(default_factory=list)
poller: str = "Central"
hostgroups: str = ""
hostgroups: list[str] = field(default_factory=list)
check_command: str = ""
check_command_args: str = ""
timezone: str = ""
macros: list[Macro] = field(default_factory=list)
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> "Host":
def from_dict(cls, raw: dict[str, Any]) -> Host:
return cls(
name=_clean(raw.get("name")),
alias=_clean(raw.get("alias")),
address=_clean(raw.get("address")),
templates=[_clean(t) for t in raw.get("templates") or [] if _clean(t)],
poller=_clean(raw.get("poller")) or "Central",
hostgroups=_clean(raw.get("hostgroups")),
# Ancien format : une chaine unique separee par | ou par virgule.
hostgroups=_liste(raw.get("hostgroups")),
check_command=_clean(raw.get("check_command")),
check_command_args=_clean(raw.get("check_command_args")),
timezone=_clean(raw.get("timezone")),
macros=[Macro.from_dict(m) for m in raw.get("macros") or []],
)
JOURS = ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday")
JOURS_FR = {
"monday": "lundi",
"tuesday": "mardi",
"wednesday": "mercredi",
"thursday": "jeudi",
"friday": "vendredi",
"saturday": "samedi",
"sunday": "dimanche",
}
# Etats qui declenchent une notification, tels que Centreon les nomme.
OPTIONS_HOTE = {"d": "Indisponible", "u": "Inatteignable", "r": "Retabli", "f": "Bascule", "s": "Maintenance"}
OPTIONS_SERVICE = {
"w": "Alerte",
"c": "Critique",
"u": "Inconnu",
"r": "Retabli",
"f": "Bascule",
"s": "Maintenance",
}
@dataclass
class Calendrier:
"""Periode temporelle Centreon : quand une notification a le droit de partir."""
name: str = ""
alias: str = ""
jours: dict[str, str] = field(default_factory=dict)
# Certains calendriers existent des l'installation de Centreon : les
# recreer ferait echouer le deploiement. Ils figurent quand meme dans le
# projet, pour qu'on voie a quoi les perimetres se referent.
creer: bool = True
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> Calendrier:
jours = raw.get("jours") or {}
return cls(
name=_clean(raw.get("name")),
alias=_clean(raw.get("alias")),
jours={j: _clean(jours.get(j)) for j in JOURS if _clean(jours.get(j))},
creer=bool(raw.get("creer", True)),
)
@dataclass
class Bloc:
"""Un element du corps du message.
Quatre natures : une macro Centreon, un lien, un texte fixe, ou la sortie
du plugin mise en avant. L'ordre de la liste est l'ordre d'affichage.
"""
type: str = "macro"
libelle: str = ""
valeur: str = ""
TYPES = ("macro", "lien", "texte", "sortie")
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> Bloc:
nature = _clean(raw.get("type")) or "macro"
return cls(
type=nature if nature in cls.TYPES else "macro",
libelle=_clean(raw.get("libelle")),
valeur=_clean(raw.get("valeur")),
)
@dataclass
class Perimetre:
"""Un perimetre de notification : qui est prevenu, quand, et avec quel message.
L'interet est de separer ce qui differe reellement d'un domaine a l'autre.
Un incident applicatif n'a pas le meme destinataire, le meme calendrier ni
le meme contenu qu'un incident systeme : le message doit porter le nom de
l'application, son responsable et la procedure de reprise.
"""
name: str = ""
description: str = ""
calendrier: str = "24x7"
contacts: list[str] = field(default_factory=list)
groupe: str = ""
options_hote: str = "d,u,r"
options_service: str = "w,c,u,r"
intervalle: int = 30
# Ce qui personnalise le message, au-dela des macros de Centreon.
application: str = ""
responsable: str = ""
procedure: str = ""
criticite: str = ""
impact: str = ""
couleur: str = "#2f6f9f"
sujet_hote: str = "[$NOTIFICATIONTYPE$] $HOSTNAME$ est $HOSTSTATE$"
sujet_service: str = "[$NOTIFICATIONTYPE$] $HOSTNAME$ / $SERVICEDESC$ est $SERVICESTATE$"
# Corps du message. Vides, les blocs par defaut s'appliquent.
blocs_hote: list[Bloc] = field(default_factory=list)
blocs_service: list[Bloc] = field(default_factory=list)
@property
def slug(self) -> str:
return re.sub(r"[^a-z0-9]+", "-", self.name.lower()).strip("-") or "perimetre"
@classmethod
def from_dict(cls, raw: dict[str, Any]) -> Perimetre:
defauts = cls()
try:
intervalle = int(raw.get("intervalle", defauts.intervalle))
except (TypeError, ValueError):
intervalle = defauts.intervalle
return cls(
name=_clean(raw.get("name")),
description=_clean(raw.get("description")),
calendrier=_clean(raw.get("calendrier")) or defauts.calendrier,
contacts=[_clean(c) for c in raw.get("contacts") or [] if _clean(c)],
groupe=_clean(raw.get("groupe")),
options_hote=_clean(raw.get("options_hote")) or defauts.options_hote,
options_service=_clean(raw.get("options_service")) or defauts.options_service,
intervalle=intervalle,
application=_clean(raw.get("application")),
responsable=_clean(raw.get("responsable")),
procedure=_clean(raw.get("procedure")),
criticite=_clean(raw.get("criticite")),
impact=_clean(raw.get("impact")),
couleur=_clean(raw.get("couleur")) or defauts.couleur,
sujet_hote=_clean(raw.get("sujet_hote")) or defauts.sujet_hote,
sujet_service=_clean(raw.get("sujet_service")) or defauts.sujet_service,
blocs_hote=[Bloc.from_dict(b) for b in raw.get("blocs_hote") or []],
blocs_service=[Bloc.from_dict(b) for b in raw.get("blocs_service") or []],
)
@dataclass
class Prerequis:
"""Ce qu'il faut installer sur le collecteur pour que les sondes tournent.
Volontairement separe du CLAPI : ces commandes s'executent sur un serveur,
elles ne doivent jamais etre melangees au code de configuration ni jouees
sans relecture.
"""
paquets_debian: list[str] = field(default_factory=list)
paquets_rhel: list[str] = field(default_factory=list)
verifications: list[str] = field(default_factory=list)
notes: str = ""
@property
def vide(self) -> bool:
return not (self.paquets_debian or self.paquets_rhel or self.verifications or self.notes)
@classmethod
def from_dict(cls, raw: dict[str, Any] | None) -> Prerequis:
raw = raw or {}
paquets = raw.get("paquets") or {}
return cls(
paquets_debian=[_clean(p) for p in paquets.get("debian") or [] if _clean(p)],
paquets_rhel=[_clean(p) for p in paquets.get("rhel") or [] if _clean(p)],
verifications=[_clean(v) for v in raw.get("verifications") or [] if _clean(v)],
notes=str(raw.get("notes") or "").strip(),
)
def fusionner(self, autre: Prerequis) -> None:
for source, cible in (
(autre.paquets_debian, self.paquets_debian),
(autre.paquets_rhel, self.paquets_rhel),
(autre.verifications, self.verifications),
):
for valeur in source:
if valeur not in cible:
cible.append(valeur)
if autre.notes and autre.notes not in self.notes:
self.notes = f"{self.notes}\n\n{autre.notes}".strip()
# Un nom de paquet reste un nom de paquet : ni espace, ni separateur de
# commande. Le fichier genere est relu par un humain, mais autant qu'aucune
# soumission ne puisse y glisser autre chose.
MOTIF_PAQUET = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._+-]{0,80}$")
# Une macro Centreon : $NOM$, y compris les personnalisees $_HOSTXXX$.
MOTIF_MACRO = re.compile(r"^\$[A-Z_][A-Z0-9_]*\$$")
@dataclass
class Project:
name: str = "Nouveau projet"
centreon_version: str = "24.x"
centreon_version: str = VERSION_PAR_DEFAUT
prefix: str = ""
plugins_dir: str = "/usr/lib/centreon/plugins"
poller: str = "Central"
@@ -169,6 +412,11 @@ class Project:
service_templates: list[ServiceTemplate] = field(default_factory=list)
host_templates: list[HostTemplate] = field(default_factory=list)
hosts: list[Host] = field(default_factory=list)
groupes_hotes: list[GroupeHote] = field(default_factory=list)
calendriers: list[Calendrier] = field(default_factory=list)
perimetres: list[Perimetre] = field(default_factory=list)
notif_dir: str = "/usr/share/centreon/notifications"
prerequis: Prerequis = field(default_factory=Prerequis)
schema: int = SCHEMA_VERSION
@property
@@ -176,11 +424,12 @@ class Project:
return CENTREON_VERSIONS.get(self.centreon_version, {}).get("macro_fields", 5)
@classmethod
def from_dict(cls, raw: dict[str, Any] | None) -> "Project":
def from_dict(cls, raw: dict[str, Any] | None) -> Project:
raw = raw or {}
version = _clean(raw.get("centreon_version")) or "24.x"
version = _clean(raw.get("centreon_version")) or VERSION_PAR_DEFAUT
version = VERSIONS_HISTORIQUES.get(version, version)
if version not in CENTREON_VERSIONS:
version = "24.x"
version = VERSION_PAR_DEFAUT
return cls(
name=_clean(raw.get("name")) or "Nouveau projet",
centreon_version=version,
@@ -192,12 +441,17 @@ class Project:
service_templates=[ServiceTemplate.from_dict(s) for s in raw.get("service_templates") or []],
host_templates=[HostTemplate.from_dict(h) for h in raw.get("host_templates") or []],
hosts=[Host.from_dict(h) for h in raw.get("hosts") or []],
groupes_hotes=[GroupeHote.from_dict(g) for g in raw.get("groupes_hotes") or []],
calendriers=[Calendrier.from_dict(c) for c in raw.get("calendriers") or []],
perimetres=[Perimetre.from_dict(p) for p in raw.get("perimetres") or []],
notif_dir=_clean(raw.get("notif_dir")) or "/usr/share/centreon/notifications",
prerequis=Prerequis.from_dict(raw.get("prerequis")),
)
def to_dict(self) -> dict[str, Any]:
return asdict(self)
def merge(self, other: "Project") -> list[str]:
def merge(self, other: Project) -> list[str]:
"""Ajoute les objets d'un autre projet, en ignorant les noms deja pris."""
skipped: list[str] = []
@@ -214,6 +468,10 @@ class Project:
add(self.service_templates, other.service_templates, "Modele de service")
add(self.host_templates, other.host_templates, "Modele d'hote")
add(self.hosts, other.hosts, "Hote")
add(self.groupes_hotes, other.groupes_hotes, "Groupe d'hotes")
add(self.calendriers, other.calendriers, "Calendrier")
add(self.perimetres, other.perimetres, "Perimetre")
self.prerequis.fusionner(other.prerequis)
return skipped
@@ -221,6 +479,16 @@ class Project:
# Validation
# --------------------------------------------------------------------------- #
def fuseaux_horaires() -> list[str]:
"""Fuseaux connus du systeme, au format attendu par Centreon."""
try:
import zoneinfo
return sorted(zoneinfo.available_timezones())
except Exception:
return []
def validate(project: Project) -> list[dict[str, str]]:
"""Retourne la liste des problemes, du bloquant au simple avertissement."""
@@ -248,6 +516,9 @@ def validate(project: Project) -> list[dict[str, str]]:
check_names(project.service_templates, "Modele de service")
check_names(project.host_templates, "Modele d'hote")
check_names(project.hosts, "Hote")
check_names(project.groupes_hotes, "Groupe d'hotes")
check_names(project.calendriers, "Calendrier")
check_names(project.perimetres, "Perimetre")
command_names = {c.name for c in project.commands}
htpl_names = {h.name for h in project.host_templates}
@@ -282,7 +553,19 @@ def validate(project: Project) -> list[dict[str, str]]:
for htpl in project.host_templates:
_check_macros(htpl.macros, f"Modele d'hote {htpl.name}", issues)
connus = set(fuseaux_horaires())
for objet in (*project.host_templates, *project.hosts):
if objet.timezone and connus and objet.timezone.lstrip(":") not in connus:
error(f"{objet.name} : fuseau horaire inconnu, {objet.timezone}")
groupes = {g.name for g in project.groupes_hotes}
for host in project.hosts:
for groupe in host.hostgroups:
if groupe not in groupes:
warn(
f"Hote {host.name} : le groupe {groupe} n'est pas dans le projet, "
"il devra exister sur le central."
)
if not host.address:
error(f"Hote {host.name} : l'adresse est vide.")
for template in host.templates:
@@ -290,6 +573,56 @@ def validate(project: Project) -> list[dict[str, str]]:
warn(f"Hote {host.name} : modele d'hote inconnu, {template}")
_check_macros(host.macros, f"Hote {host.name}", issues)
perimetres = {p.name for p in project.perimetres}
for modele in (*project.host_templates, *project.service_templates):
if modele.perimetre and modele.perimetre not in perimetres:
warn(
f"{modele.name} : le perimetre de notification {modele.perimetre} n'est pas "
"dans le projet."
)
calendriers = {c.name for c in project.calendriers}
for perimetre in project.perimetres:
# Un calendrier vide devient 24x7 a la lecture : le perimetre pointe
# alors le calendrier du central, ce que l'avertissement ci-dessous
# signale.
if perimetre.calendrier not in calendriers:
warn(
f"Perimetre {perimetre.name} : le calendrier {perimetre.calendrier} n'est pas "
"dans le projet, il devra exister sur le central."
)
if not perimetre.contacts and not perimetre.groupe:
warn(
f"Perimetre {perimetre.name} : ni contact ni groupe, personne ne sera prevenu."
)
for nom, blocs in (("hote", perimetre.blocs_hote), ("service", perimetre.blocs_service)):
for numero, bloc in enumerate(blocs, start=1):
if bloc.type in ("macro", "lien", "sortie") and not bloc.valeur:
error(
f"Perimetre {perimetre.name}, bloc {nom} n{chr(176)}{numero} : "
"aucune valeur, il n'affichera rien."
)
if bloc.type == "macro" and bloc.valeur and not MOTIF_MACRO.match(bloc.valeur):
error(
f"Perimetre {perimetre.name}, bloc {bloc.libelle or numero} : "
f"{bloc.valeur} n'a pas la forme d'une macro Centreon."
)
for lettre in perimetre.options_hote.replace(" ", "").split(","):
if lettre and lettre not in OPTIONS_HOTE:
error(f"Perimetre {perimetre.name} : option d'hote inconnue, {lettre}")
for lettre in perimetre.options_service.replace(" ", "").split(","):
if lettre and lettre not in OPTIONS_SERVICE:
error(f"Perimetre {perimetre.name} : option de service inconnue, {lettre}")
for calendrier in project.calendriers:
if calendrier.creer and not calendrier.jours:
warn(f"Calendrier {calendrier.name} : aucune plage horaire, il ne notifiera jamais.")
for paquet in (*project.prerequis.paquets_debian, *project.prerequis.paquets_rhel):
if not MOTIF_PAQUET.match(paquet):
error(f"Prerequis : nom de paquet invalide, {paquet}")
if not project.commands and not project.service_templates and not project.host_templates:
warn("Le projet est vide.")
+546
View File
@@ -0,0 +1,546 @@
"""Scripts de notification PHP, un par perimetre.
Centreon appelle une commande de notification ; cette commande execute le
script genere ici, avec les macros de l'evenement en arguments. Le script met
en forme le message et le remet a sendmail.
Le corps du message est compose de blocs : une macro, un lien, un texte fixe,
ou la sortie du plugin. L'ordre des blocs est l'ordre d'affichage. Un gabarit
HTML unique sert au script comme a l'apercu, pour qu'ils ne divergent jamais.
Comme pour le reste d'Enclume, le site ecrit ces fichiers et ne les execute
jamais : ils sont deposes sur le collecteur par l'administrateur, apres
relecture.
"""
from __future__ import annotations
from html import escape
from .model import Bloc, Perimetre, Project
SHEBANG = "#!/usr/bin/php -c /etc/php.ini"
# Couleurs par etat, reprises du vocabulaire de la supervision.
COULEURS = {
"UP": "#3fb98a",
"OK": "#3fb98a",
"DOWN": "#e0575b",
"CRITICAL": "#e0575b",
"UNREACHABLE": "#b06ab3",
"WARNING": "#e7a93f",
"UNKNOWN": "#8ca0b6",
"PENDING": "#8ca0b6",
}
# --------------------------------------------------------------------------- #
# Macros proposees dans l'editeur
#
# Noms verifies dans la documentation Centreon. La liste ne cherche pas a etre
# exhaustive : l'editeur accepte toute macro saisie a la main, y compris les
# personnalisees $_HOSTXXX$ et $_SERVICEXXX$.
# --------------------------------------------------------------------------- #
MACROS: list[dict[str, str]] = [
# L'evenement
{"macro": "$NOTIFICATIONTYPE$", "libelle": "Type de notification", "portee": "les deux"},
{"macro": "$NOTIFICATIONAUTHOR$", "libelle": "Auteur de l'action", "portee": "les deux"},
{"macro": "$NOTIFICATIONAUTHORALIAS$", "libelle": "Auteur, nom complet", "portee": "les deux"},
{"macro": "$NOTIFICATIONCOMMENT$", "libelle": "Commentaire de l'auteur", "portee": "les deux"},
{"macro": "$LONGDATETIME$", "libelle": "Date et heure", "portee": "les deux"},
{"macro": "$SHORTDATETIME$", "libelle": "Date et heure, format court", "portee": "les deux"},
# L'hote
{"macro": "$HOSTNAME$", "libelle": "Nom de l'hote", "portee": "les deux"},
{"macro": "$HOSTALIAS$", "libelle": "Alias de l'hote", "portee": "les deux"},
{"macro": "$HOSTADDRESS$", "libelle": "Adresse de l'hote", "portee": "les deux"},
{"macro": "$HOSTSTATE$", "libelle": "Etat de l'hote", "portee": "les deux"},
{"macro": "$HOSTSTATETYPE$", "libelle": "Etat confirme ou en cours", "portee": "les deux"},
{"macro": "$HOSTOUTPUT$", "libelle": "Sortie du controle de l'hote", "portee": "hote"},
{"macro": "$LONGHOSTOUTPUT$", "libelle": "Sortie longue de l'hote", "portee": "hote"},
{"macro": "$HOSTDURATION$", "libelle": "Duree dans cet etat", "portee": "les deux"},
{"macro": "$HOSTATTEMPT$", "libelle": "Tentative en cours", "portee": "hote"},
{"macro": "$MAXHOSTATTEMPTS$", "libelle": "Tentatives maximales", "portee": "hote"},
{"macro": "$HOSTNOTES$", "libelle": "Notes de l'hote", "portee": "les deux"},
{"macro": "$HOSTNOTESURL$", "libelle": "URL des notes de l'hote", "portee": "les deux"},
{"macro": "$HOSTACTIONURL$", "libelle": "URL d'action de l'hote", "portee": "les deux"},
{"macro": "$HOSTGROUPNAMES$", "libelle": "Groupes de l'hote", "portee": "les deux"},
{"macro": "$HOSTPERFDATA$", "libelle": "Donnees de performance de l'hote", "portee": "hote"},
{"macro": "$HOSTID$", "libelle": "Identifiant de l'hote", "portee": "les deux"},
{
"macro": "$TOTALHOSTSERVICESCRITICAL$",
"libelle": "Services critiques sur l'hote",
"portee": "les deux",
},
# Le service
{"macro": "$SERVICEDESC$", "libelle": "Nom du service", "portee": "service"},
{"macro": "$SERVICESTATE$", "libelle": "Etat du service", "portee": "service"},
{"macro": "$SERVICESTATETYPE$", "libelle": "Etat confirme ou en cours", "portee": "service"},
{"macro": "$SERVICEOUTPUT$", "libelle": "Sortie du controle", "portee": "service"},
{"macro": "$LONGSERVICEOUTPUT$", "libelle": "Sortie longue du controle", "portee": "service"},
{"macro": "$SERVICEDURATION$", "libelle": "Duree dans cet etat", "portee": "service"},
{"macro": "$SERVICEATTEMPT$", "libelle": "Tentative en cours", "portee": "service"},
{"macro": "$MAXSERVICEATTEMPTS$", "libelle": "Tentatives maximales", "portee": "service"},
{"macro": "$SERVICENOTES$", "libelle": "Notes du service", "portee": "service"},
{"macro": "$SERVICENOTESURL$", "libelle": "URL des notes du service", "portee": "service"},
{"macro": "$SERVICEACTIONURL$", "libelle": "URL d'action du service", "portee": "service"},
{"macro": "$SERVICEGROUPNAMES$", "libelle": "Groupes du service", "portee": "service"},
{"macro": "$SERVICEPERFDATA$", "libelle": "Donnees de performance", "portee": "service"},
{"macro": "$SERVICEID$", "libelle": "Identifiant du service", "portee": "service"},
{
"macro": "$LASTSERVICESTATECHANGE$",
"libelle": "Dernier changement d'etat",
"portee": "service",
},
# Le destinataire
{"macro": "$CONTACTNAME$", "libelle": "Nom du destinataire", "portee": "les deux"},
{"macro": "$CONTACTALIAS$", "libelle": "Alias du destinataire", "portee": "les deux"},
{"macro": "$CONTACTEMAIL$", "libelle": "Courriel du destinataire", "portee": "les deux"},
]
# --------------------------------------------------------------------------- #
# Gabarits, partages par le script PHP et l'apercu
# --------------------------------------------------------------------------- #
GABARIT_HTML = """<html><body style="margin:0;padding:0;background:#f4f6f8;\
font-family:Segoe UI,Helvetica,Arial,sans-serif">\
<div style="max-width:640px;margin:24px auto;background:#fff;\
border:1px solid #dde2e8;border-radius:4px;overflow:hidden">\
<div style="background:__TEINTE__;color:#fff;padding:14px 18px;font-size:16px;\
font-weight:600">__ETAT__ &mdash; __PERIMETRE__</div>\
<div style="padding:18px">\
<table style="border-collapse:collapse;font-size:14px;width:100%">__LIGNES__</table>\
__BLOCS__\
__PROCEDURE__\
</div></div></body></html>"""
GABARIT_LIGNE = """<tr>\
<td style="padding:6px 14px 6px 0;color:#667;white-space:nowrap;vertical-align:top">__LIBELLE__</td>\
<td style="padding:6px 0;color:#111">__VALEUR__</td></tr>"""
GABARIT_SORTIE = """<div style="margin-top:16px;padding:12px;background:#f4f6f8;\
border-radius:3px;font-family:Consolas,monospace;font-size:13px;color:#222">__VALEUR__</div>"""
GABARIT_LIEN = """<tr>\
<td style="padding:6px 14px 6px 0;color:#667;white-space:nowrap;vertical-align:top">__LIBELLE__</td>\
<td style="padding:6px 0"><a href="__URL__" style="color:__TEINTE__">__URL__</a></td></tr>"""
GABARIT_PROCEDURE = """<p style="margin-top:18px;font-size:14px">\
<a href="__URL__" style="color:__TEINTE__;font-weight:600">Procedure de reprise</a></p>"""
def _php(valeur: str) -> str:
"""Litteral PHP entre guillemets simples."""
return "'" + str(valeur).replace("\\", "\\\\").replace("'", "\\'") + "'"
def nom_script(perimetre: Perimetre) -> str:
return f"notif-{perimetre.slug}.php"
# --------------------------------------------------------------------------- #
# Composition du corps
# --------------------------------------------------------------------------- #
def blocs_par_defaut(perimetre: Perimetre, pour: str) -> list[Bloc]:
"""Le message livre sans composition : l'essentiel d'un incident."""
est_service = pour == "service"
blocs = [
Bloc("macro", "Hote", "$HOSTNAME$"),
Bloc("macro", "Adresse", "$HOSTADDRESS$"),
]
if est_service:
blocs += [
Bloc("macro", "Service", "$SERVICEDESC$"),
Bloc("macro", "Etat", "$SERVICESTATE$"),
Bloc("macro", "Depuis", "$SERVICEDURATION$"),
Bloc("macro", "Tentative", "$SERVICEATTEMPT$"),
]
else:
blocs += [
Bloc("macro", "Etat", "$HOSTSTATE$"),
Bloc("macro", "Depuis", "$HOSTDURATION$"),
]
blocs += [
Bloc("macro", "Date", "$LONGDATETIME$"),
Bloc("macro", "Auteur", "$NOTIFICATIONAUTHOR$"),
Bloc("macro", "Commentaire", "$NOTIFICATIONCOMMENT$"),
]
for libelle, valeur in (
("Application", perimetre.application),
("Responsable", perimetre.responsable),
("Criticite", perimetre.criticite),
("Impact", perimetre.impact),
):
if valeur:
blocs.append(Bloc("texte", libelle, valeur))
blocs.append(
Bloc("sortie", "Sortie du controle", "$SERVICEOUTPUT$" if est_service else "$HOSTOUTPUT$")
)
return blocs
def blocs_effectifs(perimetre: Perimetre, pour: str) -> list[Bloc]:
choisis = perimetre.blocs_service if pour == "service" else perimetre.blocs_hote
return list(choisis) if choisis else blocs_par_defaut(perimetre, pour)
def _cle(index: int) -> str:
return f"b{index}"
def commande_notification(projet: Project, perimetre: Perimetre, pour: str) -> str:
"""Ligne de la commande Centreon : elle transporte les macros des blocs."""
chemin = f"{projet.notif_dir}/{nom_script(perimetre)}"
etat = "SERVICESTATE" if pour == "service" else "HOSTSTATE"
morceaux = [
chemin,
f"--type={pour}",
"--notification='$NOTIFICATIONTYPE$'",
"--destinataire='$CONTACTEMAIL$'",
"--hote='$HOSTNAME$'",
f"--etat='${etat}$'",
]
if pour == "service":
morceaux.append("--service='$SERVICEDESC$'")
for index, bloc in enumerate(blocs_effectifs(perimetre, pour), start=1):
if bloc.type in ("macro", "lien", "sortie"):
morceaux.append(f"--{_cle(index)}='{bloc.valeur}'")
return " ".join(morceaux)
def _blocs_php(perimetre: Perimetre, pour: str) -> str:
lignes = []
for index, bloc in enumerate(blocs_effectifs(perimetre, pour), start=1):
champs = [f"'type' => {_php(bloc.type)}", f"'libelle' => {_php(bloc.libelle)}"]
if bloc.type == "texte":
champs.append(f"'valeur' => {_php(bloc.valeur)}")
else:
champs.append(f"'cle' => {_php(_cle(index))}")
lignes.append(" [" + ", ".join(champs) + "],")
return "\n".join(lignes)
def rendre_script(projet: Project, perimetre: Perimetre) -> str:
"""Le script PHP d'un perimetre, hote et service dans le meme fichier."""
couleurs = "\n".join(f" {_php(k)} => {_php(v)}," for k, v in COULEURS.items())
return f"""{SHEBANG}
<?php
/**
* Notification Centreon — perimetre « {perimetre.name} »
* {perimetre.description}
*
* Genere par Enclume. A relire avant installation.
* Depose dans {projet.notif_dir}/ et rendu executable par l'utilisateur du
* moteur de supervision.
*
* Le corps du message est compose de blocs, dans l'ordre defini au moment de
* la generation. Chaque bloc de type macro, lien ou sortie recoit sa valeur
* par un argument de la ligne de commande.
*/
$perimetre = {_php(perimetre.name)};
$couleur = {_php(perimetre.couleur)};
$procedure = {_php(perimetre.procedure)};
$expediteur = getenv('ENCLUME_EXPEDITEUR') ?: 'centreon@' . php_uname('n');
$blocsHote = [
{_blocs_php(perimetre, "host")}
];
$blocsService = [
{_blocs_php(perimetre, "service")}
];
$couleurs = [
{couleurs}
];
$gabaritMessage = <<<'HTML'
{GABARIT_HTML}
HTML;
$gabaritLigne = <<<'HTML'
{GABARIT_LIGNE}
HTML;
$gabaritLien = <<<'HTML'
{GABARIT_LIEN}
HTML;
$gabaritSortie = <<<'HTML'
{GABARIT_SORTIE}
HTML;
$gabaritProcedure = <<<'HTML'
{GABARIT_PROCEDURE}
HTML;
// --- Lecture des arguments ------------------------------------------------
$type = getopt('', ['type:']);
$estService = (($type['type'] ?? '') === 'service');
$blocs = $estService ? $blocsService : $blocsHote;
$attendus = ['type:', 'notification::', 'destinataire:', 'hote:', 'etat:', 'service::'];
foreach ($blocs as $bloc) {{
if (isset($bloc['cle'])) {{
$attendus[] = $bloc['cle'] . '::';
}}
}}
$arguments = getopt('', $attendus);
foreach (['destinataire', 'hote', 'etat'] as $obligatoire) {{
if (empty($arguments[$obligatoire])) {{
fwrite(STDERR, "notification : argument manquant, --$obligatoire\\n");
exit(1);
}}
}}
$etat = strtoupper($arguments['etat']);
$teinte = $couleurs[$etat] ?? $couleur;
// --- Sujet ----------------------------------------------------------------
$sujet = $estService
? {_php(perimetre.sujet_service)}
: {_php(perimetre.sujet_hote)};
$sujet = strtr($sujet, [
'$NOTIFICATIONTYPE$' => $arguments['notification'] ?? '',
'$HOSTNAME$' => $arguments['hote'],
'$HOSTSTATE$' => $etat,
'$SERVICEDESC$' => $arguments['service'] ?? '',
'$SERVICESTATE$' => $etat,
]);
// --- Corps ----------------------------------------------------------------
$lignes = '';
$apres = '';
foreach ($blocs as $bloc) {{
$valeur = ($bloc['type'] === 'texte')
? ($bloc['valeur'] ?? '')
: ($arguments[$bloc['cle']] ?? '');
// Une macro sans valeur a l'execution ne doit pas laisser de ligne vide.
if ($valeur === '' || $valeur === null) {{
continue;
}}
if ($bloc['type'] === 'sortie') {{
$apres .= strtr($gabaritSortie, ['__VALEUR__' => htmlspecialchars($valeur)]);
continue;
}}
if ($bloc['type'] === 'lien') {{
$lignes .= strtr($gabaritLien, [
'__LIBELLE__' => htmlspecialchars($bloc['libelle']),
'__URL__' => htmlspecialchars($valeur),
'__TEINTE__' => $teinte,
]);
continue;
}}
$lignes .= strtr($gabaritLigne, [
'__LIBELLE__' => htmlspecialchars($bloc['libelle']),
'__VALEUR__' => htmlspecialchars($valeur),
]);
}}
$blocProcedure = ($procedure === '') ? '' : strtr($gabaritProcedure, [
'__URL__' => htmlspecialchars($procedure),
'__TEINTE__' => $teinte,
]);
$corps = strtr($gabaritMessage, [
'__TEINTE__' => $teinte,
'__ETAT__' => htmlspecialchars($etat),
'__PERIMETRE__' => htmlspecialchars($perimetre),
'__LIGNES__' => $lignes,
'__BLOCS__' => $apres,
'__PROCEDURE__' => $blocProcedure,
]);
// --- Envoi ----------------------------------------------------------------
$entetes = [
'MIME-Version: 1.0',
'Content-Type: text/html; charset=UTF-8',
'From: ' . $expediteur,
'X-Enclume-Perimetre: ' . $perimetre,
];
$envoye = mail($arguments['destinataire'], $sujet, $corps, implode("\\r\\n", $entetes));
if (!$envoye) {{
fwrite(STDERR, "notification : echec de l'envoi a " . $arguments['destinataire'] . "\\n");
exit(1);
}}
exit(0);
"""
def rendre_installation(projet: Project) -> str:
"""Script de depot des notifications sur le collecteur."""
lignes = [
"#!/usr/bin/env bash",
"#",
f"# Installation des scripts de notification - {projet.name}",
"# Genere par Enclume. A RELIRE AVANT EXECUTION.",
"#",
"# A executer sur le serveur qui porte le moteur de supervision, en root.",
"# Les scripts .php doivent se trouver a cote de ce fichier.",
"",
"set -euo pipefail",
"",
f'DESTINATION="{projet.notif_dir}"',
'UTILISATEUR="${UTILISATEUR:-centreon-engine}"',
"",
"if ! command -v php > /dev/null; then",
' echo "php est absent de cette machine." >&2',
" exit 1",
"fi",
"",
'mkdir -p "$DESTINATION"',
"",
]
for perimetre in projet.perimetres:
fichier = nom_script(perimetre)
lignes += [
f"# Perimetre : {perimetre.name}",
f'php -l "$(dirname "$0")/{fichier}"',
(
'install -m 0750 -o "$UTILISATEUR" -g "$UTILISATEUR" '
f'"$(dirname "$0")/{fichier}" "$DESTINATION/{fichier}"'
),
f'echo "installe : $DESTINATION/{fichier}"',
"",
]
lignes += [
"echo \"Termine. Verifier qu'un agent de transport de courrier est en place.\"",
"",
]
return "\n".join(lignes)
# --------------------------------------------------------------------------- #
# Apercu
# --------------------------------------------------------------------------- #
# Valeurs d'exemple pour les macros courantes. Une macro absente de cette table
# s'affiche sous forme de reperage, pour qu'on voie tout de meme la ligne
# qu'elle produira.
EXEMPLES_MACROS = {
"$NOTIFICATIONTYPE$": "PROBLEM",
"$NOTIFICATIONAUTHOR$": "hcornet",
"$NOTIFICATIONAUTHORALIAS$": "Hubert Cornet",
"$NOTIFICATIONCOMMENT$": "Prise en compte, intervention en cours",
"$LONGDATETIME$": "vendredi 11 septembre 2026 14:30:00",
"$SHORTDATETIME$": "11-09-2026 14:30:00",
"$HOSTNAME$": "srv-facturation-01",
"$HOSTALIAS$": "Serveur de facturation",
"$HOSTADDRESS$": "10.0.4.30",
"$HOSTSTATETYPE$": "HARD",
"$HOSTDURATION$": "0d 0h 4m 12s",
"$HOSTATTEMPT$": "3",
"$MAXHOSTATTEMPTS$": "3",
"$HOSTGROUPNAMES$": "Serveurs-Applicatifs",
"$HOSTNOTES$": "Serveur de la chaine de facturation",
"$HOSTNOTESURL$": "https://wiki.exemple.fr/srv-facturation-01",
"$HOSTACTIONURL$": "https://wiki.exemple.fr/actions/srv-facturation-01",
"$HOSTID$": "42",
"$TOTALHOSTSERVICESCRITICAL$": "2",
"$SERVICEDESC$": "App-DB-MySQL-Connection-Time",
"$SERVICESTATETYPE$": "HARD",
"$SERVICEDURATION$": "0d 0h 3m 45s",
"$SERVICEATTEMPT$": "3",
"$MAXSERVICEATTEMPTS$": "3",
"$SERVICEGROUPNAMES$": "Bases-de-donnees",
"$SERVICENOTES$": "Connexion a l'instance de facturation",
"$SERVICENOTESURL$": "https://wiki.exemple.fr/mysql-facturation",
"$SERVICEACTIONURL$": "https://wiki.exemple.fr/actions/mysql",
"$SERVICEPERFDATA$": "connection_time=0.004s;1;5;0;",
"$SERVICEID$": "317",
"$LASTSERVICESTATECHANGE$": "1789123456",
"$CONTACTNAME$": "hcornet",
"$CONTACTALIAS$": "Hubert Cornet",
"$CONTACTEMAIL$": "[email protected]",
}
ETATS_EXEMPLE = {"service": "CRITICAL", "host": "DOWN"}
SORTIES_EXEMPLE = {
"service": "CRITICAL: Cannot connect to MySQL server on '10.0.4.30' (111 Connection refused)",
"host": "CRITICAL - Host unreachable (rta nan, lost 100%)",
}
def _valeur_exemple(macro: str, pour: str) -> str:
if macro in ("$SERVICEOUTPUT$", "$HOSTOUTPUT$", "$LONGSERVICEOUTPUT$", "$LONGHOSTOUTPUT$"):
return SORTIES_EXEMPLE[pour]
if macro in ("$SERVICESTATE$", "$HOSTSTATE$"):
return ETATS_EXEMPLE[pour]
return EXEMPLES_MACROS.get(macro, f"[{macro}]")
def apercu(projet: Project, perimetre: Perimetre, pour: str = "service") -> dict[str, str]:
"""Le message tel qu'il partira, rempli de valeurs d'exemple.
Utilise exactement les gabarits embarques dans le script PHP : ce qui est
montre ici est ce qui sera envoye.
"""
etat = ETATS_EXEMPLE.get(pour, ETATS_EXEMPLE["service"])
teinte = COULEURS.get(etat, perimetre.couleur)
sujet = perimetre.sujet_service if pour == "service" else perimetre.sujet_hote
sujet = sujet.replace("$NOTIFICATIONTYPE$", "PROBLEM")
sujet = sujet.replace("$HOSTNAME$", EXEMPLES_MACROS["$HOSTNAME$"])
sujet = sujet.replace("$SERVICEDESC$", EXEMPLES_MACROS["$SERVICEDESC$"])
sujet = sujet.replace("$HOSTSTATE$", etat).replace("$SERVICESTATE$", etat)
lignes = ""
apres = ""
for bloc in blocs_effectifs(perimetre, pour):
valeur = bloc.valeur if bloc.type == "texte" else _valeur_exemple(bloc.valeur, pour)
if not valeur:
continue
if bloc.type == "sortie":
apres += GABARIT_SORTIE.replace("__VALEUR__", escape(valeur))
elif bloc.type == "lien":
lignes += (
GABARIT_LIEN.replace("__LIBELLE__", escape(bloc.libelle))
.replace("__URL__", escape(valeur))
.replace("__TEINTE__", teinte)
)
else:
lignes += GABARIT_LIGNE.replace("__LIBELLE__", escape(bloc.libelle)).replace(
"__VALEUR__", escape(valeur)
)
procedure = (
""
if not perimetre.procedure
else GABARIT_PROCEDURE.replace("__URL__", escape(perimetre.procedure)).replace(
"__TEINTE__", teinte
)
)
corps = (
GABARIT_HTML.replace("__TEINTE__", teinte)
.replace("__ETAT__", escape(etat))
.replace("__PERIMETRE__", escape(perimetre.name))
.replace("__LIGNES__", lignes)
.replace("__BLOCS__", apres)
.replace("__PROCEDURE__", procedure)
)
return {
"sujet": sujet,
"corps": corps,
"destinataire": EXEMPLES_MACROS["$CONTACTEMAIL$"],
"commande": commande_notification(projet, perimetre, pour),
"script": f"{projet.notif_dir}/{nom_script(perimetre)}",
}
+102 -2
View File
@@ -7,7 +7,40 @@ le projet de l'utilisateur, qui les modifie ensuite librement.
from __future__ import annotations
from .catalog import Pack
from .model import Command, HostTemplate, Macro, Project, ServiceTemplate
from .model import (
Calendrier,
Command,
GroupeHote,
HostTemplate,
Macro,
Perimetre,
Prerequis,
Project,
ServiceTemplate,
)
# Calendriers standards proposes par les packs. Les noms sont ceux que Centreon
# livre par defaut : un pack qui demande 24x7 tombera sur le calendrier existant
# du central si celui-ci le definit deja.
# Calendriers livres par Centreon a l'installation : un pack qui s'y refere ne
# doit pas tenter de les creer, TP;ADD echouerait sur un objet existant.
CALENDRIERS_CENTREON = {"24x7", "none", "workhours", "nonworkhours"}
CALENDRIERS_STANDARD = {
"24x7": {
"alias": "Tous les jours, toute la journee",
"jours": dict.fromkeys(
("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"),
"00:00-24:00",
),
},
"Heures-Ouvrees": {
"alias": "8h-18h du lundi au vendredi",
"jours": dict.fromkeys(
("monday", "tuesday", "wednesday", "thursday", "friday"), "08:00-18:00"
),
},
}
def _macro(macro) -> Macro:
@@ -19,10 +52,15 @@ def _macro(macro) -> Macro:
)
def pack_to_project(pack: Pack, only_defaults: bool = True, service_parent: str = "generic-active-service-custom") -> Project:
def pack_to_project(
pack: Pack,
only_defaults: bool = True,
service_parent: str = "generic-active-service-custom",
) -> Project:
"""Construit un projet ne contenant que les objets du pack."""
project = Project(name=pack.name)
project.prerequis = Prerequis.from_dict(pack.prerequis)
project.commands = []
project.service_templates = []
@@ -39,6 +77,67 @@ def pack_to_project(pack: Pack, only_defaults: bool = True, service_parent: str
htpl.snmp_community = "public"
project.host_templates = [htpl]
# --- Groupe d'hotes livre avec le pack ----------------------------------
# Un hote sans groupe devient introuvable des que le parc grandit, et les
# droits comme les filtres s'appuient dessus. Le pack en propose donc un.
if pack.groupe_hote:
project.groupes_hotes = [
GroupeHote(
name=str(pack.groupe_hote.get("name") or ""),
alias=str(pack.groupe_hote.get("alias") or pack.name),
)
]
# --- Chaine de notification --------------------------------------------
notification = pack.notification or {}
perimetre_nom = ""
if notification:
calendrier = notification.get("calendrier")
if isinstance(calendrier, dict):
# Le pack apporte son propre calendrier : modifier les plages
# d'Apache ne doit pas toucher celles de tout le central.
calendrier_nom = str(calendrier.get("name") or "")
modele = CALENDRIERS_STANDARD.get(str(calendrier.get("modele") or "24x7"))
project.calendriers = [
Calendrier(
name=calendrier_nom,
alias=str(calendrier.get("alias") or modele["alias"]),
jours=dict(modele["jours"]),
creer=True,
)
]
else:
# Ancienne forme : une reference a un calendrier existant.
calendrier_nom = str(calendrier or "24x7")
modele = CALENDRIERS_STANDARD.get(calendrier_nom)
if modele:
project.calendriers = [
Calendrier(
name=calendrier_nom,
alias=str(modele["alias"]),
jours=dict(modele["jours"]),
creer=calendrier_nom not in CALENDRIERS_CENTREON,
)
]
perimetre_nom = str(notification.get("perimetre") or pack.name)
project.perimetres = [
Perimetre(
name=perimetre_nom,
description=str(notification.get("description") or pack.description),
calendrier=calendrier_nom,
groupe=str(notification.get("groupe") or ""),
options_hote=str(notification.get("options_hote") or "d,u,r"),
options_service=str(notification.get("options_service") or "w,c,r"),
intervalle=int(notification.get("intervalle") or 30),
criticite=str(notification.get("criticite") or ""),
impact=str(notification.get("impact") or ""),
responsable=str(notification.get("responsable") or ""),
)
]
htpl.perimetre = perimetre_nom
for svc in pack.services:
if only_defaults and not svc.enabled_by_default:
continue
@@ -54,6 +153,7 @@ def pack_to_project(pack: Pack, only_defaults: bool = True, service_parent: str
retry_interval=svc.retry_interval or 1,
max_attempts=svc.max_attempts or 3,
host_templates=[htpl.name],
perimetre=perimetre_nom,
macros=[_macro(m) for m in svc.macros],
)
)
+366
View File
@@ -0,0 +1,366 @@
"""Routes des chantiers 3 a 5 : projets enregistres, partage, soumissions.
Deux regles traversent tout ce fichier.
1. Aucun mot de passe ne franchit la porte du stockage. Tout projet ecrit en
base — enregistrement, partage, soumission — passe d'abord par
strip_secrets. Un site public n'a aucune raison de detenir le mot de passe
MySQL de qui que ce soit.
2. Rien ne s'execute. Une soumission est du texte, relu par un humain dans une
pull request avant d'atteindre le catalogue.
"""
from __future__ import annotations
import json
import re
from datetime import UTC
import yaml
from flask import Blueprint, jsonify, request
from .auth import administration_requise, connexion_requise, utilisateur_courant
from .catalog import CATEGORIES, Pack
from .config import Config
from .db import (
Partage,
Projet,
Soumission,
compter_soumissions_du_jour,
db,
maintenant,
purger_partages_expires,
)
from .gitea import ErreurGitea, ouvrir_demande
from .model import Project, strip_secrets
bp = Blueprint("donnees", __name__)
MOTIF_PACK_ID = re.compile(r"^[a-z0-9][a-z0-9-]{2,63}$")
def _projet_sans_secrets(brut: dict) -> Project:
return strip_secrets(Project.from_dict(brut))
def _corps() -> dict:
return request.get_json(force=True, silent=True) or {}
# --------------------------------------------------------------------------- #
# Chantier 3 — projets enregistres
# --------------------------------------------------------------------------- #
@bp.get("/api/projets")
@connexion_requise
def lister_projets():
utilisateur = utilisateur_courant()
projets = (
db.session.query(Projet)
.filter_by(utilisateur_id=utilisateur.id)
.order_by(Projet.maj_le.desc())
.all()
)
return jsonify([p.resume() for p in projets])
@bp.post("/api/projets")
@connexion_requise
def enregistrer_projet():
utilisateur = utilisateur_courant()
corps = _corps()
projet = _projet_sans_secrets(corps.get("project") or {})
contenu = json.dumps(projet.to_dict(), ensure_ascii=False)
if len(contenu) > Config.TAILLE_MAX_PROJET:
return jsonify({"erreur": "projet trop volumineux"}), 413
identifiant = corps.get("id")
if identifiant:
enregistrement = db.session.get(Projet, int(identifiant))
if enregistrement is None or enregistrement.utilisateur_id != utilisateur.id:
return jsonify({"erreur": "projet introuvable"}), 404
else:
nombre = db.session.query(Projet).filter_by(utilisateur_id=utilisateur.id).count()
if nombre >= Config.PROJETS_PAR_COMPTE:
return jsonify({"erreur": f"limite de {Config.PROJETS_PAR_COMPTE} projets atteinte"}), 409
enregistrement = Projet(utilisateur_id=utilisateur.id)
db.session.add(enregistrement)
enregistrement.nom = projet.name[:255] or "Projet sans nom"
enregistrement.contenu = contenu
db.session.commit()
return jsonify(enregistrement.resume())
@bp.get("/api/projets/<int:identifiant>")
@connexion_requise
def ouvrir_projet(identifiant: int):
utilisateur = utilisateur_courant()
enregistrement = db.session.get(Projet, identifiant)
if enregistrement is None or enregistrement.utilisateur_id != utilisateur.id:
return jsonify({"erreur": "projet introuvable"}), 404
return jsonify({"id": enregistrement.id, "project": json.loads(enregistrement.contenu)})
@bp.delete("/api/projets/<int:identifiant>")
@connexion_requise
def supprimer_projet(identifiant: int):
utilisateur = utilisateur_courant()
enregistrement = db.session.get(Projet, identifiant)
if enregistrement is None or enregistrement.utilisateur_id != utilisateur.id:
return jsonify({"erreur": "projet introuvable"}), 404
db.session.delete(enregistrement)
db.session.commit()
return jsonify({"statut": "supprime"})
# --------------------------------------------------------------------------- #
# Chantier 3 — partage par lien
# --------------------------------------------------------------------------- #
@bp.post("/api/partages")
def creer_partage():
if not Config.base_active():
return jsonify({"erreur": "le partage n'est pas active sur cette instance"}), 503
projet = _projet_sans_secrets(_corps().get("project") or {})
contenu = json.dumps(projet.to_dict(), ensure_ascii=False)
if len(contenu) > Config.TAILLE_MAX_PROJET:
return jsonify({"erreur": "projet trop volumineux"}), 413
purger_partages_expires()
utilisateur = utilisateur_courant()
partage = Partage.creer(
contenu=contenu,
nom=projet.name,
jours=Config.PARTAGE_JOURS,
utilisateur_id=utilisateur.id if utilisateur else None,
)
db.session.add(partage)
db.session.commit()
base = Config.URL_PUBLIQUE or request.url_root.rstrip("/")
expire = partage.expire_le
return jsonify(
{
"id": partage.id,
"url": f"{base}/p/{partage.id}",
"expire_le": expire.replace(tzinfo=expire.tzinfo or UTC).isoformat(),
"avertissement": "Les macros de type mot de passe ont ete videes avant l'enregistrement.",
}
)
@bp.get("/api/partages/<identifiant>")
def lire_partage(identifiant: str):
if not Config.base_active():
return jsonify({"erreur": "le partage n'est pas active sur cette instance"}), 503
partage = db.session.get(Partage, identifiant)
if partage is None or partage.expire:
return jsonify({"erreur": "ce lien n'existe pas ou a expire"}), 404
partage.vues += 1
db.session.commit()
return jsonify({"project": json.loads(partage.contenu)})
# --------------------------------------------------------------------------- #
# Chantier 5 — soumission de packs
# --------------------------------------------------------------------------- #
def valider_pack(texte: str) -> tuple[dict | None, list[str]]:
"""Verifie qu'un YAML soumis est un pack exploitable. Ne l'execute jamais."""
problemes: list[str] = []
if len(texte.encode("utf-8")) > Config.TAILLE_MAX_PACK:
return None, ["Le fichier depasse la taille autorisee."]
try:
brut = yaml.safe_load(texte)
except yaml.YAMLError as erreur:
return None, [f"YAML illisible : {erreur}"]
if not isinstance(brut, dict):
return None, ["Le fichier doit contenir un pack, sous forme de dictionnaire."]
identifiant = str(brut.get("id") or "").strip()
if not MOTIF_PACK_ID.match(identifiant):
problemes.append(
"L'identifiant doit faire 3 a 64 caracteres, en minuscules, chiffres et tirets."
)
categorie = str(brut.get("category") or "").strip()
if categorie not in CATEGORIES:
problemes.append(f"Categorie inconnue : {categorie or '(vide)'}")
# Les absences les plus courantes sont nommees explicitement : un
# contributeur doit lire ce qui manque, pas le nom d'une cle Python.
for cle, explication in (
("name", "Le pack doit porter un nom lisible : name."),
("host_template", "Le pack doit declarer un modele d'hote : host_template."),
("services", "Le pack doit declarer au moins une sonde, sous services."),
):
if not brut.get(cle):
problemes.append(explication)
if isinstance(brut.get("host_template"), dict) and not brut["host_template"].get("name"):
problemes.append("Le modele d'hote doit porter un nom : host_template.name.")
if problemes:
return None, problemes
try:
pack = Pack.from_dict(brut)
except KeyError as erreur:
return None, [f"Champ obligatoire absent : {erreur.args[0]}"]
except Exception as erreur:
return None, [f"Structure invalide : {erreur}"]
if not pack.services:
problemes.append("Le pack ne declare aucune sonde.")
for service in pack.services:
if ";" in service.line:
problemes.append(f"Sonde {service.name} : le point-virgule est le separateur CLAPI.")
if "$CENTREONPLUGINS$" not in service.line and "$USER1$" not in service.line:
problemes.append(
f"Sonde {service.name} : la ligne doit commencer par $CENTREONPLUGINS$ ou $USER1$."
)
from .model import MOTIF_PAQUET, Prerequis
prerequis = Prerequis.from_dict(pack.prerequis)
for paquet in (*prerequis.paquets_debian, *prerequis.paquets_rhel):
if not MOTIF_PAQUET.match(paquet):
problemes.append(f"Prerequis : nom de paquet invalide, {paquet}")
if problemes:
return None, problemes
return brut, []
@bp.post("/api/soumissions/verifier")
@connexion_requise
def verifier_soumission():
brut, problemes = valider_pack(str(_corps().get("yaml") or ""))
if problemes:
return jsonify({"valide": False, "problemes": problemes}), 200
pack = Pack.from_dict(brut)
return jsonify(
{
"valide": True,
"pack": {
"id": pack.id,
"nom": pack.name,
"categorie": pack.category,
"sondes": len(pack.services),
"modele_hote": pack.host_template.name,
},
}
)
@bp.post("/api/soumissions")
@connexion_requise
def soumettre():
utilisateur = utilisateur_courant()
if compter_soumissions_du_jour(utilisateur.id) >= Config.SOUMISSIONS_PAR_JOUR:
return jsonify({"erreur": "limite de soumissions atteinte pour aujourd'hui"}), 429
corps = _corps()
texte = str(corps.get("yaml") or "")
brut, problemes = valider_pack(texte)
if problemes:
return jsonify({"erreur": "pack invalide", "problemes": problemes}), 400
pack = Pack.from_dict(brut)
soumission = Soumission(
utilisateur_id=utilisateur.id,
pack_id=pack.id,
categorie=pack.category,
nom=pack.name,
contenu=texte,
message=str(corps.get("message") or "")[:2000],
)
db.session.add(soumission)
db.session.commit()
return jsonify(soumission.resume())
@bp.get("/api/soumissions")
@connexion_requise
def mes_soumissions():
utilisateur = utilisateur_courant()
soumissions = (
db.session.query(Soumission)
.filter_by(utilisateur_id=utilisateur.id)
.order_by(Soumission.cree_le.desc())
.limit(50)
.all()
)
return jsonify([s.resume() for s in soumissions])
# --------------------------------------------------------------------------- #
# Chantier 5 — moderation
# --------------------------------------------------------------------------- #
@bp.get("/api/moderation/soumissions")
@administration_requise
def moderation_lister():
statut = request.args.get("statut", Soumission.EN_ATTENTE)
requete = db.session.query(Soumission).order_by(Soumission.cree_le.asc())
if statut != "toutes":
requete = requete.filter_by(statut=statut)
return jsonify([s.resume(avec_auteur=True) for s in requete.limit(200).all()])
@bp.get("/api/moderation/soumissions/<int:identifiant>")
@administration_requise
def moderation_detail(identifiant: int):
soumission = db.session.get(Soumission, identifiant)
if soumission is None:
return jsonify({"erreur": "soumission introuvable"}), 404
donnees = soumission.resume(avec_auteur=True)
donnees["contenu"] = soumission.contenu
return jsonify(donnees)
@bp.post("/api/moderation/soumissions/<int:identifiant>/publier")
@administration_requise
def moderation_publier(identifiant: int):
soumission = db.session.get(Soumission, identifiant)
if soumission is None:
return jsonify({"erreur": "soumission introuvable"}), 404
if soumission.statut != Soumission.EN_ATTENTE:
return jsonify({"erreur": "soumission deja traitee"}), 409
if not Config.gitea_actif():
return jsonify({"erreur": "publication Gitea non configuree"}), 503
# Revalidation au moment de publier : le contenu a pu etre juge valide il y
# a trois semaines, sous une version anterieure des regles.
_, problemes = valider_pack(soumission.contenu)
if problemes:
return jsonify({"erreur": "le pack n'est plus valide", "problemes": problemes}), 400
try:
url = ouvrir_demande(soumission, soumission.auteur.affichage if soumission.auteur else "inconnu")
except ErreurGitea as erreur:
return jsonify({"erreur": str(erreur)}), 502
soumission.statut = Soumission.PUBLIEE
soumission.url_pr = url
soumission.traite_le = maintenant()
db.session.commit()
return jsonify(soumission.resume(avec_auteur=True))
@bp.post("/api/moderation/soumissions/<int:identifiant>/refuser")
@administration_requise
def moderation_refuser(identifiant: int):
soumission = db.session.get(Soumission, identifiant)
if soumission is None:
return jsonify({"erreur": "soumission introuvable"}), 404
if soumission.statut != Soumission.EN_ATTENTE:
return jsonify({"erreur": "soumission deja traitee"}), 409
soumission.statut = Soumission.REFUSEE
soumission.reponse = str(_corps().get("motif") or "")[:2000]
soumission.traite_le = maintenant()
db.session.commit()
return jsonify(soumission.resume(avec_auteur=True))
+1208 -55
View File
File diff suppressed because it is too large. Load diff
Loaded 100 of 123 files, more files were not shown because too many files have changed in this diff. Show more