Руководство оператора коннектора Профиль Сотрудника#

Введение#

Коннектор к АС Профиль Сотрудника предназначен для замены получения сведений о сотрудниках из КИС.

Верхнеуровневое описание алгоритма#

Сообщения из АС Профиль Сотрудника поступают в топики Kafka, откуда их получает IDM, используя Kafka коннектор с помощью задач Task employees import, Task divisions import и Task organization import.

Для каждого топика Kafka создается отдельный ресурс (EMPLOYEE PROFILE, DIVISIONS или ORGANIZATIONS, в зависимости от типа сообщений, которые отправляются в этот топик). Согласно маппингам, после получения сообщений из Kafka, IDM создает на основе сообщений shadow объекты ресурсов, а затем создает (или изменяет) связанные с этими shadow объектами объекты IDM.

Для ресурса EMPLOYEE PROFILE создание объектов IDM происходит в рамках работы задачи Task employees import. Для ресурсов DIVISIONS и ORGANIZATION маппинги прописаны в конфигурации самих ресурсов, и обработка shadow и создание/изменение объектов IDM происходит в рамках работы задач Task divisions import и Task organization import.

Ресурс EMPLOYEE PROFILE#

Импорт сообщений для ресурса EMPLOYEE PROFILE#

Загрузка сообщений в IDM для ресурса EMPLOYEE PROFILE происходит по следующему алгоритму:

Обработка сообщений Kafka выполняется задачей Task employees import. Данная задача содержит 3 activity:

  1. Получение сообщений из Kafka - задача вычитывает сообщения из топика Kafka, на который настроен ресурс EMPLOYEE PROFILE. Для настройки в задаче указывается oid ресурса, с которым она работает (подробнее смотрите в руководстве по администрированию коннектора Профиля Сотрудника).

  2. Обработка shadow - в данной activity задача выполняет следующие действия:

    1. Сопоставление с владельцем - задача проверяет, существует ли в IDM объект типа UserType с архетипом dc899045-66b7-4176-94dd-d2073d18c859 (Employees Records), который совпадает с shadow объектом по employeeNumber и givenName и additionalName (при этом, если name.middleName в shadow объекте пуст - будет применяться фильтр additionalName == null, а если name.middleName не пуст - то фильтрация будет по равенству name.middleName и additionalName). Если владельца не существует - создается новый объект IDM (Employees Records), к которому привязывается shadow.

    2. Обновление данных - задача обновляет значения атрибутов владельца согласно полученным из shadow изменениям.

  3. Обновление токена - задача обновляет токен последнего запуска, чтобы при следующем запуске начать обработку shadow с того сообщения, на котором остановилась. Задача записывает в токен timestamp последнего запуска, и потом обрабатывает только те shadow, у которых metadata/modifyTimestamp пустой или больше токена задачи. Если токен пустой – в начале обработки shadow он заполняется timestamp текущего запуска задачи. Задача вычитывает по 200 сообщений за один запуск.

Структура маппингов EMPLOYEES PROFILE#

Источник маппингов: task-employee-profile-import.xml → activity Process shadows (iterativeScripting)

Маппинги при создании владельца (createOwner)#

#

Source (Shadow/EmployeeRecord)

Target (IDM Owner)

Тип

1

employeeRecord: kisId или employeeRecord: employeeNumber

$owner/employeeNumber

employeeRecord

2

shadow: nameMiddleName

$owner/name/additional

shadow

3

shadow: nameFio

$owner/fullName

shadow

4

shadow: nameFamilyName

$owner/familyName

shadow

5

shadow: nameGivenName

$owner/givenName

shadow

6

shadow: nameMiddleName

$owner/name/middle

shadow

7

employeeRecord: title

$owner/title

employeeRecord

8

employeeRecord: organizationName

$owner/organization

employeeRecord

9

employeeRecord: beginDate

$owner/hireDate

employeeRecord

10

shadow: phoneNumbers (primary → type=11,13)

$owner/telephoneNumber

shadow (script)

11

employeeRecord: hrInfoSourceCode

$owner/extension/hrInfoSourceCode

employeeRecord

12

shadow: emails (type=other)

$owner/emailAddress

shadow (script)

13

script: getSberkisource(employeeRecord)

$owner/extension/sberkisource

script

14

script: getKiId(employeeRecord)

$owner/extension/kiId

script

15

script: getUserType(employeeRecord)

$owner/extension/userType

script

16

script: getSourceId(employeeRecord)

$owner/extension/source_id

script

17

shadow: extension.sberkisourceabbr

$owner/extension/sberkisourceabbr

shadow

Дополнительные маппинги при обновлении владельца (updateOwner)#

#

Source (Shadow/EmployeeRecord)

Target (IDM Owner)

Тип

18

shadow: OID

$owner/linkRef

shadow

19

employeeRecord: id

$owner/employmentId

employeeRecord

20

employeeRecord: isManager

$owner/extension/isManager

employeeRecord

21

employeeRecord: isVIP

$owner/extension/isVIP

employeeRecord

22

employeeRecord: categoryCode

$owner/extension/categoryCode

employeeRecord

23

employeeRecord: categoryDescr

$owner/extension/categoryDescr

employeeRecord

24

employeeRecord: groupCode

$owner/extension/groupCode

employeeRecord

25

employeeRecord: groupDescr

$owner/extension/groupDescr

employeeRecord

26

employeeRecord: balanceUnitCode

$owner/extension/balanceUnitCode

employeeRecord

27

employeeRecord: titleLong

$owner/extension/titleLong

employeeRecord

28

employeeRecord: riskCoordinator

$owner/extension/riskCoordinator

employeeRecord

29

employeeRecord: externalId

$owner/extension/externalId

employeeRecord

30

employeeRecord: employeeRegistrationId

$owner/extension/employeeRegistrationId

employeeRecord

31

employeeRecord: connectModeId

$owner/extension/connectModeId

employeeRecord

32

employeeRecord: organizationId

$owner/extension/organizationId

employeeRecord

33

shadow: profileId

$owner/extension/profileId

shadow

34

shadow: extension.goldenRecordId

$owner/extension/goldenRecordId

shadow

35

shadow: extension.birthDate

$owner/birthDate

shadow

36

shadow: extension.sex

$owner/sex

shadow

37

shadow: meta.version

$owner/extension/kisId

shadow

38

employeeRecord: deptCurator

$owner/extension/sbercbdkiouguid

employeeRecord

39

script: generatePDI(guid, hireDate) (when nickName == null)

$owner/nickName

script

40

owner.getName() (existing)

$owner/extension/sbercbdkiouguid (replace)

owner

Обработка удаления (profileDelete = true)#

Действие

Условие

Устанавливает userStatus = 0 на владельца (если userStatus == 1)

shadow: profileDelete == true

Временный пилотный workaround (CB-организации)#

Source

Target

Условие

const "d41d8cd98f00b204e9800998ecf8427e"

$owner/extension/sbercbdkiouguid

organizationId ∈ expected CB list

const "sm_aut"

$owner/extension/kiId

organizationId ∈ expected CB list

const "18"

$owner/extension/source_id

organizationId ∈ expected CB list

const "Service Manager. Внешние сотрудники"

$owner/extension/sberkisource

organizationId ∈ expected CB list

Фильтрация shadow-объектов#

Условие

Результат

profileDelete == true

Обработка удаления (userStatus = 0)

hrInfoSourceCode ∉ {1, 3, 5}

Skip (игнорируется)

organizationId ∉ expected list

Skip (игнорируется)

Иначе

findOrCreateOwner → createOwner или updateOwner

Ресурс DIVISIONS#

Импорт сообщений для ресурса DIVISIONS#

Загрузка сообщений в IDM для ресурса DIVISIONS происходит по следующему алгоритму:

Обработка сообщений Kafka выполняется задачей Task divisions import. Данная задача содержит 3 activity:

  1. Получение сообщений из Kafka - задача вычитывает сообщения из топика Kafka, на который настроен ресурс DIVISIONS. Для настройки в задаче указывается oid ресурса, с которым она работает (подробнее смотрите в руководстве по администрированию коннектора Профиля Сотрудника).

  2. Обработка сообщений - в данной activity задача выполняет следующие действия:

    1. Импорт shadow - задача производит импорт полученных сообщений Kafka как shadow объектов ресурсы DIVISIONS, которые затем обрабатываются системой IDM, и, на основе маппингов в ресурсе DIVISION, создает или изменяет объекты IDM (организации OrgType).

  3. Обновление токена - задача обновляет токен последнего запуска, чтобы при следующем запуске начать обработку shadow с того сообщения, на котором остановилась. Задача записывает в токен timestamp последнего запуска, и потом обрабатывает только те shadow, у которых metadata/modifyTimestamp пустой или больше токена задачи. Если токен пустой – в начале обработки shadow он заполняется timestamp текущего запуска задачи. Задача вычитывает по 200 сообщений за один запуск.

Структура маппингов DIVISIONS#

При импорте создаются объекты orgType - организации.

Inbound маппинги#

#

Атрибут ресурса (ref)

Source (Kafka JSON)

Target (IDM path)

Condition

1

ri:subdivisionId

subdivisionId

$focus/name

focus.getName() == null

2

ri:subdivisionId

subdivisionId

$focus/identifier

focus instanceof OrgType && focus.getIdentifier() == null

3

ri:sapGUID

sapGUID

$focus/extension/sapGUID

—

4

ri:type

type

$focus/extension/type

—

5

ri:externalId

externalId

$focus/extension/extid

—

6

ri:name

name

$focus/displayName

—

7

ri:name

name

$focus/extension/sbercbdkiouname

—

8

ri:created

created

$focus/extension/created

—

9

ri:parentId

parentId

$focus/extension/parentId

—

10

ri:organizationId

organizationId

$focus/extension/organizationId

—

11

ri:beginDate

beginDate

$focus/activation/validFrom

—

12

ri:endDate

endDate

$focus/activation/validTo

—

13

ri:managerEmployeeNumber

managerEmployeeNumber

$focus/extension/managerEmployeeNumber

—

14

ri:managerPositionExternalId

managerPositionExternalId

$focus/extension/managerPositionExternalId

—

15

ri:managerType

managerType

$focus/extension/managerType

—

16

ri:managerUserId

managerUserId

$focus/extension/managerUserId

—

17

ri:managerSapGUID

managerSapGUID

$focus/extension/managerSapGUID

—

18

ri:divisionEmployeeNumber

divisionEmployeeNumber

$focus/extension/divisionEmployeeNumber

—

19

ri:divisionPositionExternalId

divisionPositionExternalId

$focus/extension/divisionPositionExternalId

—

20

ri:divisionType

divisionType

$focus/extension/divisionType

—

21

ri:divisionUserId

divisionUserId

$focus/extension/divisionUserId

—

22

ri:divisionSapGUID

divisionSapGUID

$focus/extension/divisionSapGUID

—

23

ri:locationExternalId

locationExternalId

$focus/extension/locationExternalId

—

24

ri:locationName

locationName

$focus/extension/locationName

—

25

ri:isMain

isMain

$focus/extension/isMain

—

26

ri:hrInfoSourceCode

hrInfoSourceCode

$focus/extension/hrInfoSourceCode

—

27

ri:hrInfoSourceName

hrInfoSourceName

$focus/extension/hrInfoSourceName

—

28

ri:sbereasupfuncblockname

sbereasupfuncblockname

$focus/extension/sbereasupfuncblockname

—

Synchronization#

Ситуация

Действие

linked

synchronize

unmatched

addFocus

unlinked

link

Ресурс ORGANIZATION#

Импорт сообщений для ресурса ORGANIZATION#

Загрузка сообщений в IDM для ресурса ORGANIZATION происходит по следующему алгоритму:

Обработка сообщений Kafka выполняется задачей Task organization import. Данная задача содержит 3 activity:

  1. Получение сообщений из Kafka - задача вычитывает сообщения из топика Kafka, на который настроен ресурс ORGANIZATION. Для настройки в задаче указывается oid ресурса, с которым она работает (подробнее смотрите в руководстве по администрированию коннектора Профиля Сотрудника).

  2. Обработка сообщений - в данной activity задача выполняет следующие действия:

    1. Импорт shadow - задача производит импорт полученных сообщений Kafka как shadow объектов ресурсы ORGANIZATION, которые затем обрабатываются системой IDM, и, на основе маппингов в ресурсе ORGANIZATION, создает или изменяет объекты IDM (организации OrgType).

  3. Обновление токена - задача обновляет токен последнего запуска, чтобы при следующем запуске начать обработку shadow с того сообщения, на котором остановилась. Задача записывает в токен timestamp последнего запуска, и потом обрабатывает только те shadow, у которых metadata/modifyTimestamp пустой или больше токена задачи. Если токен пустой – в начале обработки shadow он заполняется timestamp текущего запуска задачи. Задача вычитывает по 200 сообщений за один запуск.

Структура маппингов ORGANIZATION#

При импорте создаются объекты orgType - организации.

Inbound маппинги#

#

Атрибут ресурса (ref)

Source (Kafka JSON)

Target (IDM path)

Condition

1

ri:organizationId

organizationId

$focus/name

focus.getName() == null

2

ri:organizationId

organizationId

$focus/identifier

focus instanceof OrgType && focus.getIdentifier() == null

3

ri:fullName

fullName

$focus/displayName

—

4

ri:name

name

$focus/extension/sbercbdkiouname

—

5

ri:brand

brand

$focus/extension/brand

—

6

ri:inn

inn

$focus/extension/inn

—

7

ri:legalForm

legalForm

$focus/extension/legalForm

—

8

ri:sbpId

sbpId

$focus/extension/sbpId

—

9

ri:status

status

$focus/extension/status

—

10

ri:hrInfoSourceCode

hrInfoSourceCode

$focus/extension/hrInfoSourceCode

—

11

ri:hrInfoSourceName

hrInfoSourceName

$focus/extension/hrInfoSourceName

—

12

ri:organizationTypeId

organizationTypeId

$focus/extension/organizationTypeId

—

13

ri:organizationTypeName

organizationTypeName

$focus/extension/organizationTypeName

—

Synchronization#

Ситуация

Действие

linked

synchronize

unmatched

addFocus

unlinked

link

Просмотр событий аудита#

Для отслеживания выполнения операций используется UI IDM. Чтобы найти нужную запись, следуйте инструкции:

  1. В IDM перейдите на вкладку Аудит.

  2. Добавьте фильтр по ресурсу, указав в поле Ресурс имя требуемого ресурса.

  3. Нажмите кнопку Обновить.

  4. В списке отобразятся все события конкретного ресурса.

    Если требуется отобразить конкретные операции (например, создание объекта) - укажите соответствующий тип события в поле Тип события.

Просмотр логов#

Все действия, производимые компонентом IDMX (компонент idmx-engine) логируются, логи записываются в файлы на сервере. IDMX создает файлы журнала в директории /app/idmx-engine/var/log.

Основной файл для работы - idm-engine.log. В него вносятся все логи работы IDMX.

В случае, если нужно получить логи интеграции с AD, то необходимо настроить категорию коннектора Профиль сотрудника.

Настроить категорию можно вручную согласно инструкции ниже.

  1. Перейдите в UI IDM > Система > Логирование.

  2. Перейдите в пункт Class loggers.

  3. Нажмите кнопку + и добавьте категорию ru.sbertech.idmc.connector.kafka.profile, выставив необходимый уровень логирования. В средах разработки и тестирования рекомендуется использование уровня DEBUG. В PROD-среде рекомендуется использование уровня не ниже INFO.

Дополнительные логгеры для более детальной информации:

#

Полное имя логгера (класс, от имени пишутся логи)

За что отвечает (что логирует)

Механизм

1

ru.sbertech.idmc.connector.kafka.profile.ProfileConnector

Точка входа коннектора: init() — «Initialize»; dispose() — «Configuration cleanup» и ошибка закрытия TopicReader; test() — число найденных входных топиков и ошибки retrieval описаний топиков (Execution/Timeout)

ICF Log

3

ru.sbertech.idmc.connector.kafka.profile.KafkaConfigManager

Построение конфигураций Kafka-клиентов: вывод свойств consumer и adminClient, ошибка загрузки файла дополнительных свойств

ICF Log

4

ru.sbertech.idmc.connector.kafka.profile.config.ProfileConfiguration

Валидация конфигурации коннектора: начало процедуры валидации, успешная валидация

ICF Log

5

ru.sbertech.idmc.connector.kafka.profile.handler.ExecuteQueryHandler

Операция executeQuery: ошибка создания ConnectorObject из записи Kafka (с отправкой сообщения в DLQ), прерывание обработки записи, отправка невалидного сообщения в DLQ-топик, прерывание отправки в DLQ

ICF Log

6

ru.sbertech.idmc.connector.kafka.profile.handler.SchemaHandler

Формирование ICF-схемы (SchemaOp) из JSON-схемы. *⚠️ Поле LOGGER объявлено, но не используется (dead code)

ICF Log (мертвое поле)

7

ru.sbertech.idmc.connector.kafka.profile.handler.KafkaExecutorHandler

Выполнение скриптов/команд (ScriptOnResourceOp): прерывание ожидания offset’ов consumer group (2 места)

ICF Log

8

ru.sbertech.idmc.connector.kafka.profile.provider.PropertySchemaProvider

Загрузка JSON-схемы из конфигурационного свойства schemasJson

ICF Log

9

ru.sbertech.idmc.connector.kafka.profile.JsonToConnectorObjectMapper

Маппинг JSON-сообщений в ICF ConnectorObject: ошибка пустого JSON-объекта (с бросанием ConnectorIOException), пустой JSONObject, трассировка чтения каждого атрибута (конфиденциальные значения маскируются как [hidden])

ICF Log

10

ru.sbertech.idmc.connector.kafka.profile.utils.ValidateUtils

Валидация входных параметров (ObjectClass, ResultsHandler): вывод сообщения об ошибке перед бросанием InvalidAttributeValueException

ICF Log

11

ru.sbertech.idmc.connector.kafka.profile.model.PublishCallback

Kafka producer-callback: успешная публикация сообщения (debug) или ошибка публикации (error).

SLF4J Logger