Les entités et les lieux ressemblent au même "arbre" dans GLPI, mais ils résolvent des problèmes opposés : l'entité segmente les données et les permissions ; le lieu n'est qu'une référence physique. Confondre les deux - ou concevoir la hiérarchie d'entités après que les données sont déjà entrées - est la source de reprises qui coûtent des jours. Ce guide montre comment GLPI stocke ces arbres dans la base, un plan pas à pas pour la structure et les pièges qui n'apparaissent qu'en maintenance d'environnements multi-entités.
Entité, lieu et groupe : qui fait quoi
Avant de créer le moindre nœud, fixez la frontière. Les trois mécanismes organisent GLPI, mais selon des axes différents - et le mauvais choix produit soit une fuite de données, soit une bureaucratie inutile.
| Mécanisme | Segmente la permission ? | Hiérarchique ? | Ce que l'utilisateur voit désormais | Usage typique |
|---|---|---|---|---|
| Entité | Oui (données et accès) | Oui | Uniquement les données de son entité | Filiale, client MSP, service isolé |
| Lieu | Non | Oui | Rien ne change - ce n'est qu'une étiquette physique | Bâtiment, étage, salle, baie, centre de données |
| Groupe | Partiel (tickets) | Oui | Tickets attribués à son groupe | Équipe de support, squad, astreinte |
Règle empirique de terrain : l'entité est une frontière de confidentialité, le lieu est la carte physique de l'actif, le groupe est la file de travail. Si la question est "qui a le droit de voir ceci", la réponse est presque toujours l'entité - un lieu ne cache jamais rien à personne.
Comment GLPI stocke l'arbre des entités
L'écran Administration > Entités n'est qu'une coquille au-dessus de la table glpi_entities. Chaque ligne pointe vers son parent par la colonne entities_id, garde le chemin complet dans completename et la profondeur dans level. Deux colonnes silencieuses - sons_cache et ancestors_cache - conservent l'arbre pré-calculé sous forme sérialisée ; c'est de là que lisent les filtres de visibilité, pas d'une jointure récursive au moment de la requête.
-- Arbre des entites : parent, niveau et chemin complet
SELECT e.id,
e.name AS entite,
e.completename AS chemin,
e.level AS niveau,
p.name AS entite_parent
FROM glpi_entities e
LEFT JOIN glpi_entities p ON p.id = e.entities_id
ORDER BY e.completename;
Le completename ("Siège > DSI > Support") est ce qui apparaît dans les sélecteurs et les rapports ; le level accélère les requêtes de visibilité. Retenez ces deux noms : vous auditez l'arbre par completename et GLPI décide la portée par level sans parcourir toute la table.
Héritage : ce qui descend vers les enfants (et ce qui ne descend pas)
Une entité enfant n'hérite pas automatiquement des données de la mère - elle hérite de la configuration marquée comme récursive. Catégories, SLA, règles métier, modèles de notification et lieux portent la paire (entities_id, is_recursive) : pour valoir sur tout l'arbre, l'élément doit se trouver sur l'entité racine (entities_id = 0) avec is_recursive = 1. Créer une catégorie à l'intérieur d'un enfant la piège là, et les sœurs ne la voient pas.
-- Categories ITIL NON partagees sur tout l'arbre
-- (un item global correct a entities_id = 0 et is_recursive = 1)
SELECT id, name, entities_id, is_recursive
FROM glpi_itilcategories
WHERE NOT (entities_id = 0 AND is_recursive = 1);
L'erreur courante est de créer une catégorie ITIL "juste pour ce client" et de découvrir ensuite que la moitié de l'exploitation ne la voit pas. En maintenance, nous exécutons cette vérification avant toute mise en production multi-entités : un élément qui devrait être global et n'est pas en (0, récursif) est un bug qui attend le premier ticket.
Pas à pas : concevoir la structure avant les données
- Listez les frontières de confidentialité réelles (qui ne DOIT PAS voir quoi). Chaque frontière dure devient une entité ; le reste est un lieu ou un groupe.
- Dessinez l'arbre sur papier avec au plus trois niveaux. La profondeur prélève un péage sur chaque sélecteur et rapport.
- Créez les entités par l'interface, de haut en bas - jamais par SQL (voir pièges).
- Configurez sur la racine ce qui est commun (catégories, SLA, notifications) en cochant
is_recursive; ne descendez vers un enfant que ce qui lui est exclusif. - Ce n'est qu'alors que vous enregistrez utilisateurs, actifs et tickets. Déplacer des données entre entités ensuite coûte cher et entraîne les pièces jointes.
Lieux : la hiérarchie physique et le champ que tout le monde oublie
La table glpi_locations est hiérarchique par son propre locations_id (parent), mais chaque lieu appartient aussi à une entité (entities_id) et possède is_recursive. Un lieu créé dans un enfant n'apparaît pas dans les autres entités sauf s'il est récursif - le même mécanisme que les catégories. Et la valeur 0 dans locations_id n'est pas nulle : c'est la sentinelle "aucun lieu".
-- Ordinateurs sans lieu defini, par entite
SELECT e.completename AS entite,
COUNT(*) AS sans_lieu
FROM glpi_computers c
JOIN glpi_entities e ON e.id = c.entities_id
WHERE c.locations_id = 0 -- 0 = aucun (sentinelle), pas NULL
AND c.is_deleted = 0
GROUP BY e.completename
ORDER BY sans_lieu DESC;
Un inventaire sans lieu est le schéma silencieux qui explose au premier incident physique ("dans quelle baie est-il ?"). La requête ci-dessus devient un indicateur d'hygiène de CMDB que nous suivons par entité, pas une surprise en pleine nuit.
Pièges de terrain
Le pire de tous : créer une entité directement dans la base par SQL. La ligne entre, mais sons_cache et ancestors_cache de la mère ne sont pas recalculés - et comme les filtres de visibilité lisent de ces caches, l'entité devient invisible pour getSonsOf(). Le symptôme est cruel : l'entité existe dans la table, apparaît dans un SELECT, mais disparaît des sélecteurs et de l'arbre de l'interface. Nous avons appris à la dure à ne jamais créer d'entité par INSERT : c'est la création par l'écran qui recalcule les caches. Si un import hérité est déjà entré par SQL, la correction consiste à rouvrir et enregistrer chaque entité par l'interface pour forcer la reconstruction de l'arbre.
- Traiter l'entité 0 comme vide - l'entité racine a
id = 0, qui est un id VALIDE. Le code et les intégrations qui testentif (!entities_id)écartent la racine par accident ; dans les composants select2, la valeur de la racine est""(chaîne vide), jamais"0". - Un document qui disparaît quand on déplace un ticket - la pièce jointe (
Document_Item) exige que le document soit dans la même entité que le ticket. Déplacer le ticket vers une autre entité sans emporter le document casse l'accès à la pièce jointe. - Un lieu partagé sans récursion - créer une baie ou une salle dans un enfant en attendant que le siège la voie : sans
is_recursive, chaque entité ne voit que ses propres lieux. - Trop d'entités - chaque entité multiplie la configuration (catégories, SLA, notifications, attribution de profil par entité). Dix entités quasi identiques coûtent dix fois la maintenance. Si la seule différence entre deux domaines est un rapport, utilisez un groupe ou un lieu, pas une entité.
Checklist de structure organisationnelle
- Cartographiez les frontières de confidentialité avant de toucher à GLPI ; seules celles-ci deviennent des entités.
- Plafonnez l'arbre des entités à trois niveaux de profondeur.
- Créez les entités par l'interface, jamais par SQL.
- Configurez le commun sur la racine avec
is_recursive = 1; ne descendez que l'exclusif. - Traitez
idetlocations_idégaux à0comme une valeur valide, pas comme vide. - Exécutez les vérifications d'élément global non partagé et d'actif sans lieu avant chaque mise en production.
Besoin de concevoir (ou de sauver) une structure multi-entités sans reprise, ou de géoréférencer vos lieux sur une carte ? NexTool déploie et maintient des environnements GLPI multi-entités avec l'arbre revu de bout en bout, et le module Geolocation place vos lieux sur la carte. Parlez à notre équipe de déploiement et de maintenance.
Révisé par l'équipe NexTool Solutions.