Организации и местоположения в GLPI выглядят как одно и то же «дерево», но решают противоположные задачи: организация разделяет данные и права; местоположение — лишь физическая привязка. Путать их или проектировать иерархию организаций после того, как данные уже внесены, — источник переделок, которые стоят дней работы. Это руководство показывает, как GLPI хранит эти деревья в базе, даёт пошаговый план проектирования структуры и описывает ловушки, которые проявляются только при сопровождении сред с несколькими организациями.
Организация, местоположение и группа: кто за что отвечает
Прежде чем создавать какой-либо узел, зафиксируйте границу. Все три механизма упорядочивают GLPI, но по разным осям, и неверный выбор приводит к утечке данных или к бюрократии без пользы.
| Механизм | Разделяет права? | Иерархический? | Что начинает видеть пользователь | Типичное применение |
|---|---|---|---|---|
| Организация | Да (данные и доступ) | Да | Только данные своей организации | Филиал, клиент MSP, изолированный отдел |
| Местоположение | Нет | Да | Ничего не меняется — это лишь физическая метка | Здание, этаж, помещение, стойка, дата-центр |
| Группа | Частично (заявки) | Да | Заявки, назначенные своей группе | Команда поддержки, squad, дежурство |
Практическое правило: организация — это граница конфиденциальности, местоположение — физическая карта актива, группа — очередь работы. Если вопрос звучит как «кто может это видеть», ответ почти всегда — организация; местоположение никогда ничего ни от кого не скрывает.
Как GLPI хранит дерево организаций
Экран Администрирование > Организации — это оболочка над таблицей glpi_entities. Каждая строка указывает на родителя через столбец entities_id, хранит полный путь в completename и глубину в level. Два незаметных столбца — sons_cache и ancestors_cache — хранят предвычисленное дерево в сериализованном виде; именно из них читают фильтры видимости, а не из рекурсивного JOIN во время запроса.
-- Arvore de entidades: pai, nivel e caminho completo
SELECT e.id,
e.name AS entidade,
e.completename AS caminho,
e.level AS nivel,
pai.name AS entidade_pai
FROM glpi_entities e
LEFT JOIN glpi_entities pai ON pai.id = e.entities_id
ORDER BY e.completename;
completename («Matriz > TI > Suporte») — это то, что отображается в селекторах и отчётах; level ускоряет запросы видимости. Запомните эти два имени: по completename вы проверяете дерево, а по level GLPI определяет область видимости, не сканируя всю таблицу.
Наследование: что спускается к дочерним (и что нет)
Дочерняя организация не наследует данные родительской автоматически — она наследует конфигурацию, помеченную как рекурсивная. Категории, SLA, бизнес-правила, шаблоны уведомлений и местоположения несут пару (entities_id, is_recursive): чтобы действовать во всём дереве, объект должен находиться в корневой организации (entities_id = 0) с is_recursive = 1. Категория, созданная внутри дочерней организации, остаётся привязанной к ней, и соседние организации её не видят.
-- Categorias ITIL que NAO estao compartilhadas para toda a arvore
-- (um item global correto tem entities_id = 0 e is_recursive = 1)
SELECT id, name, entities_id, is_recursive
FROM glpi_itilcategories
WHERE NOT (entities_id = 0 AND is_recursive = 1);
Типичная ошибка — завести категорию ITIL «только для этого клиента», а потом обнаружить, что половина операции её не видит. При сопровождении мы выполняем эту проверку перед любым go-live с несколькими организациями: объект, который должен быть глобальным, но не находится в (0, рекурсивно), — это баг, ждущий первой заявки.
Пошагово: спроектируйте структуру до данных
- Перечислите реальные границы конфиденциальности (кто НЕ должен видеть что). Каждая жёсткая граница становится организацией; всё остальное — местоположение или группа.
- Нарисуйте дерево на бумаге максимум с тремя уровнями. Глубина взимает плату в каждом селекторе и отчёте.
- Создавайте организации через интерфейс, сверху вниз, — никогда через SQL (см. ловушки).
- Настройте в корне то, что является общим (категории, SLA, уведомления), отметив
is_recursive; в дочернюю организацию опускайте только то, что относится исключительно к ней. - Только после этого заводите пользователей, активы и заявки. Перемещать данные между организациями потом дорого, и это тянет за собой вложения.
Местоположения: физическая иерархия и поле, о котором все забывают
Таблица glpi_locations иерархична за счёт собственного locations_id (родитель), но каждое местоположение также принадлежит организации (entities_id) и имеет is_recursive. Местоположение, созданное внутри дочерней организации, не появляется в других организациях, если оно не рекурсивное, — тот же механизм, что и у категорий. А значение 0 в locations_id не равно null: это сигнальное значение «нет местоположения».
-- Computadores sem localizacao definida, por entidade
SELECT e.completename AS entidade,
COUNT(*) AS sem_localizacao
FROM glpi_computers c
JOIN glpi_entities e ON e.id = c.entities_id
WHERE c.locations_id = 0 -- 0 = nenhuma (sentinela), nao NULL
AND c.is_deleted = 0
GROUP BY e.completename
ORDER BY sem_localizacao DESC;
Инвентаризация без местоположений — тихий паттерн, который взрывается при первом физическом инциденте («в какой стойке это стоит?»). Запрос выше становится индикатором гигиены CMDB, который мы отслеживаем по организациям, а не сюрпризом посреди ночи.
Практические ловушки
Худшая из всех — создавать организацию прямо в базе через SQL. Строка добавляется, но sons_cache и ancestors_cache родителя не пересчитываются, а поскольку фильтры видимости читают из этих кешей, организация становится невидимой для getSonsOf(). Симптом жестокий: организация есть в таблице, видна в SELECT, но пропадает из селекторов и дерева в интерфейсе. Мы на собственном горьком опыте научились никогда не создавать организацию через INSERT: кеши пересчитывает именно создание через экран. Если устаревший импорт уже прошёл через SQL, исправление — открыть и сохранить каждую организацию через интерфейс, чтобы принудительно пересчитать дерево.
- Считать организацию 0 пустой — корневая организация имеет
id = 0, и это ДОПУСТИМЫЙ id. Код и интеграции, проверяющиеif (!entities_id), по ошибке отбрасывают корень; в компонентах select2 значение корня —""(пустая строка), а не"0". - Документ, пропадающий при перемещении заявки — вложение (
Document_Item) требует, чтобы документ находился в той же организации, что и заявка. Перемещение заявки в другую организацию без документа ломает доступ к вложению. - Общее местоположение без рекурсии — создать стойку или помещение в дочерней организации в расчёте, что головная его увидит: без
is_recursiveкаждая организация видит только свои местоположения. - Слишком много организаций — каждая организация умножает конфигурацию (категории, SLA, уведомления, назначение профилей по организациям). Десять почти одинаковых организаций стоят в десять раз больше в сопровождении. Если единственное различие между двумя подразделениями — отчёт, используйте группу или местоположение, а не организацию.
Чек-лист организационной структуры
- Определите границы конфиденциальности до того, как трогать GLPI; только они становятся организациями.
- Ограничьте дерево организаций тремя уровнями глубины.
- Создавайте организации через интерфейс, никогда через SQL.
- Настраивайте общее в корне с
is_recursive = 1; опускайте вниз только исключительное. - Считайте
idиlocations_id, равные0, допустимым значением, а не пустым. - Перед каждым go-live запускайте проверки глобальных объектов без общего доступа и активов без местоположения.
Нужно спроектировать (или спасти) структуру с несколькими организациями без переделок либо привязать местоположения к карте? NexTool внедряет и сопровождает среды GLPI с несколькими организациями, проверяя дерево от начала до конца, а модуль Geolocation выводит ваши местоположения на карту. Свяжитесь с нашей командой внедрения и сопровождения.
Проверено командой NexTool Solutions.