Механизм показа живых данных из внешних ИС прямо в карточках объектов инвентаризации и выполнения действий во внешних ИС (отправка SMS, сброс пароля). Не путать с интеграциями через REST API — там внешние скрипты ходят в инвентаризацию, здесь наоборот: инвентаризация обращается во внешние системы.
Архитектура и контракт провайдера (для разработчиков) — в docs/dev/integrations.md.
params-local.php (ключ integrations),
выключенная интеграция не оставляет следов в интерфейсе.runtime/integrations_cache/, общий на инстанс.Секреты (токены, пароли сервисных учёток) живут только в
params-local.php, в БД они не попадают.
Добавить провайдеров в params-local.php и создать RBAC-права командой
php yii rbac/init (право view-integration-<id> — видеть панели,
edit-integration-<id>-<действие> — выполнять действие; раздаются ролям
через штатный интерфейс /rbac/). Доступ к интеграциям следует той же
модели авторизации, что и остальное приложение (useRBAC/authorizedView,
см. Настройка): панель — как «просмотр»,
действие — как «изменение». В полностью открытом режиме (по умолчанию)
интеграции доступны всем; включение RBAC/аутентификации ограничивает их
ровно так же, как обычные операции.
Кому уже доступно при включённом RBAC. Пользователю с глобальным
правом edit доступны все действия интеграций (SMS, сброс пароля),
с глобальным view — все панели. Отдельные права *-integration-*
нужны лишь для тонкой настройки (например, дать хелпдеску сброс пароля,
не выдавая глобальный edit).
'integrations' => [
// Отправка SMS через шлюз (иконки у телефонов в карточке сотрудника
// + форма отправки на произвольный номер)
'sms' => [
'class' => \app\components\integrations\providers\SmsProvider::class,
'url' => 'https://sms-gw.local/send?phone={phone}&text={text}',
// Шлюз часто отвечает 200 и при отказе, поэтому ответ разбирается:
// по умолчанию отказом считается ответ с маркерами ERROR, FAIL,
// NOT_FOUND, NO_MESSAGE_GIVEN, DENIED, INVALID. Если у вашего шлюза
// другой формат - задайте regexp успешного ответа:
//'successPattern' => '/^OK\b/i',
],
// Панель телефонии в карточке VoIP-телефона: прогрессивный статус
// (в БД / в Asterisk / зарегистрирован / онлайн) с 4 индикаторами,
// IP и модель телефона, кнопка перехода в Web-UI абонента,
// дублирования вызова. Работает через REST API приложения
// ast22-phones (endpoint /api/v1/subscribers/status).
'pbx' => [
'class' => \app\components\integrations\providers\HttpTemplateProvider::class,
'title' => 'Телефония',
'appliesTo' => ['model' => \app\models\Techs::class, 'attribute' => 'isVoipPhone'],
'binding' => '{phone}',
// request - backend-URL, достижимый С СЕРВЕРА ARMS:
'request' => 'http://phones.local:8080/api/v1/subscribers/status?extension={binding}',
'headers' => ['Authorization' => 'Bearer <токен сервисного пользователя>'],
// таймаут запроса (по умолчанию 5с; телефония с AMI к Asterisk
// может отвечать дольше - поднимите, если панель «недоступна»):
'timeout' => 10,
// Кнопка перехода в Web-UI телефонии появляется автоматически -
// база берётся из host:port у request. web указывайте ЯВНО только
// если браузерный адрес телефонии отличается от backend-адреса
// request (напр. request идёт на имя контейнера, а браузер - на
// localhost):
//'web' => 'http://phones.local:8080',
// путь абонента в Web-UI ({id} = subscriber.id), при необходимости
// подгоните под роутинг вашей телефонии:
'webSubscriber' => '/subscriber/view?id={id}',
'panel' => ['title' => 'Телефония', 'ttl' => 30,
'template' => '@app/components/integrations/providers/views/pbx/status.php'],
],
// Учётка ActiveDirectory в карточке сотрудника: панель-справка
// (статус учётки, смена/истечение пароля, последний вход) и действия
// с учёткой. Использует уже настроенный ldap-компонент
// (config/ldap.php), отдельной учётки не требует.
//
// Действия - кнопки в панели, появляются при включённом провайдере
// 'sms' по живому состоянию учётки в AD:
// - «сбросить пароль» - у найденной учётки;
// - «создать учётную запись» (нужен usersOu) - у активного
// сотрудника, чьей учётки в AD нет (в том числе вовсе без логина -
// он предгенерируется по регламенту сквозных учёток: «фамилия.и»
// транслитом, не более 12 знаков (ограничение SAP; не влезло -
// обрезка с конца вместе с разделительной точкой), однофамильцам
// добавляется номер: smirnov.a2, popandopolo7); в форме: логин
// (занятость проверяется при открытии), дерево OU, группы; после
// создания логин записывается в карточку сотрудника. Атрибуты
// учётки заполняются строго по схеме скрипта синхронизации
// inventory-to-ad.ps1 (ФИО, должность, подразделение, организация,
// ИНН, табельный, org_id, почта, телефоны в формате синхронизации) -
// очередной прогон синхронизации такую учётку не переписывает;
// - «восстановить учётную запись» (нужны usersOu+dismissedOu) - у
// отключённой учётки в контейнере уволенных (куда её переносит
// скрипт увольнения, зеркаля путь): включение + новый пароль +
// переезд обратно по зеркальному пути (можно выбрать другое OU).
//
// Все действия именные: исполнитель вводит СВОИ учётные данные AD
// (нужны делегированные права: Reset Password; Create user objects
// на OU; Write members на группах). Пароль всегда генерируется
// автоматически (по умолчанию «произносимый» - проще продиктовать;
// можно выбрать случайный), соответствует парольной политике и НЕ
// показывается администратору - его узнаёт только пользователь из
// SMS (поэтому смена при входе не требуется). Перед отправкой SMS
// выполняется НЕДЕСТРУКТИВНАЯ предпроверка (без записи в AD): верны
// ли креды исполнителя и есть ли у него нужные права - чтобы не
// отправить SMS впустую; если после этого SMS не доставлено - в AD
// ничего не меняется.
'ad' => [
'class' => \app\components\integrations\providers\AdUserProvider::class,
// AD опрашивается при каждом открытии карточки (устаревший статус
// учётки недопустим). Задайте cacheTtl в секундах, только если
// контроллер домена далеко и панель заметно тормозит:
//'cacheTtl' => 300,
// настройки пароля/SMS (общие для всех действий):
//'defaultLength' => 12, //длина пароля по умолчанию в форме
//'smsText' => 'Ваш новый пароль: {password}',
//'sms' => 'sms', //id SMS-провайдера, если он назван иначе
// создание и восстановление учёток: пары корней «рабочий ↔
// уволенные» - строго те же, что в конфиге скрипта увольнения
// ($inventory2ad_sync в ad-usermanagement: u_OUDN/f_OUDN).
// Увольнение переносит учётку из users-корня в dismissed-корень
// той же пары с сохранением подпути; восстановление зеркалит
// строго обратно в рамках своей пары. В форме создания доступны
// поддеревья всех users-корней (сотрудники + внешние контрагенты):
//'ouPairs' => [
// ['users' => 'OU=Пользователи,DC=corp,DC=local',
// 'dismissed' => 'OU=Азимут,OU=Уволенные,DC=corp,DC=local'],
// ['users' => 'OU=External,DC=corp,DC=local',
// 'dismissed' => 'OU=External,OU=Уволенные,DC=corp,DC=local'],
//],
// одна пара может быть задана и просто скалярами:
//'usersOu' => 'OU=Пользователи,DC=corp,DC=local', //корень рабочих учёток (включает создание)
//'dismissedOu' => 'OU=Уволенные,DC=corp,DC=local', //корень уволенных (включает восстановление)
//'groupsOu' => 'OU=Группы,DC=corp,DC=local', //где искать группы для формы (не задан = весь каталог)
//'defaultGroups' => ['Пользователи JIRA'], //предвыбранные группы (имена или DN)
//'upnSuffix' => null, //суффикс UPN (не задан = account_suffix ldap-компонента)
],
// Справка ActiveDirectory в карточке ОС: где учётка компьютера лежит
// в дереве AD (путь по OU) и в каких группах состоит - по группам
// раздаются политики и доступы. Тот же ldap-компонент, что и у 'ad'
'ad-comp' => [
'class' => \app\components\integrations\providers\AdComputerProvider::class,
// по умолчанию опрашиваются только Windows-ОС (у остальных учётки
// компьютера в AD обычно нет):
//'windowsOnly' => false,
],
// Панель Zabbix в карточке ОС/оборудования: базовые метрики узла
// (аптайм, загрузка CPU и памяти, заполнение дисков), активные
// проблемы (сработавшие триггеры) и ссылка на узел в Zabbix.
// Привязка объекта к узлу - hostid в external_links (ключ
// Zabbix.hostid), его пишет скрипт синхронизации arms.zabbix; пока
// hostid не записан, панель ищет узел по FQDN/имени (в БД не пишет).
// Плюс колонка «доступность + аптайм» в списках ОС/оборудования:
// скрыта по умолчанию, включается в персонализации таблицы
// (шестерёнка над списком); показывается только у объектов с
// записанным hostid (поиска по именам в списках нет).
'zabbix' => [
'class' => \app\components\integrations\providers\ZabbixProvider::class,
'api' => 'https://zabbix.local/zabbix/api_jsonrpc.php',
'token' => '<API-токен сервисного пользователя Zabbix>',
'web' => 'https://zabbix.local/zabbix', //для ссылки на узел
//'verifySsl' => true, //по умолчанию сертификат не проверяется
//'metrics' => false, //не показывать аптайм/CPU/память/диски (и аптайм в колонке списков)
//'staleAfter' => 600, //с какого возраста данных писать «устарели»
//'cacheTtl' => 60,
//'cellTtl' => 30, //свежесть ячеек колонки в списках (мин. 15)
// Одна карточка вместо двух: спрятать отдельную карточку Zabbix
// и встроить её содержимое в «Постановку на мониторинг» (под
// вердиктом; рисуется, когда узел на мониторинге или заведён в
// Zabbix - у прочих узлов пропадает «узел не найден»). Требует
// включённого 'zabbix-sync':
//'embedded' => true,
],
// Панель «Постановка на мониторинг» в карточке ОС/оборудования:
// попадёт ли узел в Zabbix при синхронизации arms.zabbix и в каком
// виде. В карточке - бейдж вердикта (будет добавлен / на мониторинге
// / не ставится); клик по нему открывает окно с причинами и
// совпавшими правилами, «подробно» там же раскрывает полный журнал:
// все проверенные правила и на каком условии срезались.
// Источник - explain.php скрипта arms.zabbix (отвечает
// по одному узлу за доли секунды, в Zabbix не ходит, ничего не
// пишет). Имена наборов/правил берутся из rules.priv.php скрипта,
// если там заданы. Ключ обязан быть 'zabbix-sync' (путь view).
'zabbix-sync' => [
'class' => \app\components\integrations\providers\ZabbixSyncProvider::class,
'url' => 'https://synchost/arms.zabbix/explain.php',
'token' => '<$explainToken из config.priv.php скрипта arms.zabbix>',
//'title' => 'Постановка на мониторинг',
//'verifySsl' => true, //по умолчанию сертификат не проверяется
//'cacheTtl' => 0, //0 = обновлять при каждом открытии карточки
//'timeout' => 5,
//'zabbix' => 'zabbix', //id провайдера Zabbix для встраивания,
// если он назван иначе (само встраивание включается флагом
// 'embedded' => true в конфиге провайдера Zabbix, см. выше)
],
// «Порт коммутатора»: где адрес объекта виден в сети (коммутатор,
// VLAN, порт). Открывается по клику иконки поиска рядом с MAC-адресом
// (в карточке сама не рисуется: опрос занимает секунды и дёргает
// сетевое оборудование). Опрашивает коммутаторы сервис
// arms.macsearch, поставленный на машину с доступом к сетевому
// оборудованию (у сервера инвентаризации такого доступа обычно нет),
// но СОСТАВ опроса собирает сама инвентаризация: оборудование с типом
// модели «Коммутатор», заполненным IP и неархивным состоянием, по
// площадке объекта. Поэтому в выдаче коммутаторы - ссылками на свои
// карточки, а порты, связанные с другими коммутаторами (по «Сетевым
// портам»), помечаются как транзитные.
// В карточке самого коммутатора появляется вторая панель - «Что
// подключено к портам»: по кнопке снимается таблица MAC целиком и
// раскладывается по портам (что за портом - ссылкой на объект).
// Ключ обязан быть 'macsearch' (путь view-файлов).
'macsearch' => [
'class' => \app\components\integrations\providers\MacSearchProvider::class,
'url' => 'http://macsearch.local:8088', //база сервиса
'token' => '<токен из config.priv.json сервиса arms.macsearch>',
//'title' => 'Порт коммутатора',
//'autoPanel' => true, //рисовать панель в карточке автоматически,
// как у остальных интеграций (по умолчанию только по клику иконки)
//'scope' => 'place', //область опроса ПО УМОЛЧАНИЮ: 'place' - площадка,
// где стоит объект, 'all' - все коммутаторы. В меню у адреса есть оба
// пункта, так что это лишь то, что предлагается первым
//'switchTypes' => ['net_switch'], //коды типов оборудования (TechTypes.code),
// которые считаем коммутаторами; напр. ['net_switch','net_router']
//'transitFrom' => 4, //с какого числа адресов на порту считать, что за
// ним сеть, а не устройство (карточка коммутатора, «Что подключено к
// портам»). Два-три адреса - штатное дело: телефон с ПК за ним,
// виртуалки. Связи «Сетевых портов» эту оценку перебивают
//'bridgeToSwitchPorts' => ['internet','lan','switch','sw'], //как на
// устройствах-мостах (телефон с ПК за ним) подписан порт к коммутатору:
// подсказка, какой порт предложить первым в цепочке «порт → телефон →
// ПК»; в строке предложения он переключается
//'bridgeToDevicePorts' => ['pc','comp'], //...и порт к устройству за мостом
//'maxTargets' => 200, //предел коммутаторов в одном опросе
//'maxMacs' => 3, //сколько адресов объекта искать
//'includeLinked' => false, //не брать адреса привязанной ОС/АРМ (по умолчанию берутся)
//'wait' => 25, //сколько сервис держит запрос, прежде чем ответить «идёт»
//'timeout' => 30, //таймаут HTTP, обязан быть больше wait
//'cacheTtl' => 600, //ttl панели; у сервиса свой кэш такой же длины
//'maxAttempts' => 3, //сколько раз панель перезапросит себя, пока идёт опрос
//'verifySsl' => true, //по умолчанию сертификат не проверяется
],
],
Обновление со старой схемы ad-reset. Раньше сброс пароля был
отдельным провайдером ad-reset; теперь это действие провайдера ad.
При обновлении: убрать из params-local.php ключ ad-reset (его опции
defaultLength/smsText переносятся в ad), перезапустить
php yii rbac/init (право действия теперь называется
edit-integration-ad-reset-password) и перевыдать его ролям, которым
сброс был выдан точечно; у ролей с глобальным edit ничего не меняется.
Старые записи журнала остаются под провайдером ad-reset.
HttpTemplateProvider — универсальный провайдер для простых случаев
«одна панель по одному GET-запросу с JSON-ответом»: применимость,
запрос и рендер задаются целиком конфигом, писать PHP-класс не нужно.
Подробности опций — в docblock класса.
Каждое действие (и успешное, и неудачное) пишется в журнал: кто, когда, над каким объектом, с каким результатом. Шаги составных действий (сброс пароля → SMS) связываются ссылкой на инициатора. Секреты (пароли, тексты SMS) в журнал не попадают.
Просмотр — в админ-меню (иконка «шестерёнка») → Журнал интеграций
(/integrations-log): список с фильтрами по интеграции, действию,
результату, дате и инициатору; по клику — карточка записи со связанными
шагами составного действия. Журнал только читается (создание/правка/
удаление недоступны).
Результат записи: ok — выполнено, error — не выполнено, run —
начато, но не завершено (например, действие прервалось на середине).
Панели ходят во внешние ИС с сервера, поэтому проблемы удобнее ловить там же (юнит-тесты в сеть не ходят):
php yii ldap/ping
php yii zabbix/ping
ldap/ping, ldap/account <login>, ldap/computer <имя>,
ldap/auth <login> <пароль>, ldap/can-reset <кому> <исполнитель>
<пароль> — доступность контроллера домена, данные учётки, путь в
дереве и группы компьютера, проверка кредов и права на сброс (в AD
ничего не пишет).zabbix/ping — доступность API и валидность токена; zabbix/find
<имя> — найти hostid узла; zabbix/host <hostid> — узел и его
проблемы; zabbix/items <hostid> — item’ы метрик (распознан ли ключ,
есть ли свежее значение); zabbix/object <класс> <id> (например
zabbix/object comps 42) — сквозная проверка: применимость, привязка
из external_links и то, что реально покажет панель в карточке.