Документация

К списку статей
03. Коннекторы под капотом: KSC / 1С OData / syslog-evtx

Аудитория: ИТ-администратор, интегратор при пилоте. Закрывает вопрос: №3 («как подключить наш KSC / нашу 1С, к чему цепляется коннектор?»). Сценарии: S3 — подключаем боевой KSC заказчика; S4 — добавляем новый тип источника.


Короткий ответ

Источник телеметрии подключается через один контракт — протокол Collector с единственным методом collect(tenant, since) → Iterable[TelemetryRecord]. На стенде источник читает CSV-выгрузку (fixture) — это «боевая сигнатура»: интерфейс ровно тот, что будет у реального коннектора. Чтобы подключить боевой KSC/1С/журналы, нужно реализовать тот же протокол и зарегистрировать его — приём, планировщик и статистика при этом не меняются. Сейчас поддержаны три типа источника: ksc_sql, odata_1c, syslog_evtx.


Контракт коннектора

Весь контракт — один dataclass факта и один Protocol источника:

@dataclass(frozen=True)
class TelemetryRecord:
    tabel_no: str          # СЫРОЙ табельный — обезличивается на приёме, в БД не хранится
    sys_code: str          # код системы источника → приём резолвит в sys_id
    activity_date: str     # ISO-дата YYYY-MM-DD
    tx_count: int          # число транзакций за день
    session_minutes: int   # минуты активной сессии за день
    raw_product: str = ""  # СЫРОЕ имя ПО (для Recognition Parser, если sys_code пуст)

class Collector(Protocol):
    source_type: str
    def collect(self, tenant_id, since=None) -> Iterable[TelemetryRecord]: ...

Что важно понимать администратору:

  • Коннектор отдаёт сырьё (табельный, сырое имя ПО) — но не хранит его и **не

обезличивает**: обезличивание делает приём (см. статью 02).

  • Коннектор не вычисляет «активный день»: он отдаёт session_minutes, а приём сам решает

is_active_day по порогу. Источник поставляет факты, а не выводы.

  • since (необязательный) — отдавать записи начиная с даты; так делается инкрементальный сбор.
Три типа источника (и почему они «за одной сигнатурой»)

Реестр коннекторов (_REGISTRY) сопоставляет тип источника его реализации:

source_typeЧто это в боюЧто отдаёт
ksc_sqlВыгрузка из Kaspersky Security Center (SQL-экспорт инвентаря/активности)По-станционная активность ПО
odata_1c1С через интерфейс ODataСеансы/активность в конфигурациях 1С
syslog_evtxsyslog / Windows Event Log (evtx)Запуски процессов, сессии

Все три обслуживаются одним классом FixtureFileCollector(source_type) — он читает CSV по типу источника. Тип только выбирает источник; формат TelemetryRecord для всех одинаков. Объединение всех источников арендатора = его полный набор фактов (метод сбора у каждой системы один, без двойного учёта).

Какой источник обслуживает какую систему — задаётся полем collect_method системы по правилу: odata → odata_1c, syslog/evtx_log → syslog_evtx, остальное → ksc_sql. То есть «1С собирается через OData, антивирус через KSC» — это свойство системы в реестре, а не отдельная настройка коннектора.


S3. Как подключить боевой источник (паттерн «боевая сигнатура»)

Замена fixture на реальный коннектор — это реализация интерфейса, без правок ядра:

  1. Написать класс с тем же протоколом, например:
   class KscSqlCollector:
       source_type = "ksc_sql"
       def collect(self, tenant_id, since=None):
           # подключиться к боевому KSC заказчика (его строка подключения — из env/конфига),
           # выполнить выгрузку, отдать TelemetryRecord на каждую строку дневной активности.
           ...
  1. Зарегистрировать его вместо fixture в _REGISTRY['ksc_sql'] (точка подмены — get_collector).
  2. Всё. Приём (ingest_activity), планировщик, прогоны (экран /collectors),

обезличивание, идемпотентность — остаются как есть. Это и есть смысл «боевой сигнатуры»: контур уже боевой, меняется только «голова», достающая данные.

Тот же паттерн использован для выдачи лицензий (ProvisioningConnector): симулятор провижининга заменяется на реального агента установки без изменения статусной машины.
S4. Как добавить новый тип источника
  1. Добавить запись в _REGISTRY (например, "scim": ScimCollector()).
  2. Дополнить правило маршрутизации collect_method → source_type, чтобы нужные системы вели

на новый тип.

  1. Добавить тип в список источников планировщика (SOURCE_TYPES) — джобы = арендаторы × типы.

Так в Эпике 5 без правок ядра добавились odata_1c и syslog_evtx к исходному ksc_sql.

Где «вход» в систему
  • HTTP-приём (если источник умеет слать сам): POST /api/{tenant}/ingest/activity,

роль collector или it_admin. Тело — батч записей + source_type.

  • Пулл по расписанию (коллектор сам забирает): контейнер collector, планировщик

дёргает get_collector(source).collect(tenant) → тот же ingest_activity. Подробно — статья 04.

Проверка на стенде
# сгенерировать фикстуры всех типов и посмотреть, что соберётся
docker compose -f docker-compose.phase1.yml up --build
docker logs licenziar-collector-1        # видны прогоны по (tenant × source)
curl http://localhost:8001/api/artek/ops-efficiency   # covered/среднее — результат сбора

На экране /collectors видно прогоны каждого источника и сколько записей применено.

Грабли
  • Неизвестный `sys_code` → запись пропускается (skippedUnknownSystem), если сырое имя

ПО не распозналось парсером. Если боевой источник шлёт свои коды — заполните raw_product, чтобы сработал фолбэк-распознаватель (см. статью 04, врезка).

  • Источник без систем у арендатора отдаёт 0 записей — это норма. Пример: у РГГУ нет

лицензированной 1С, поэтому odata_1c для неё пуст. Не считайте это ошибкой сбора.

  • Сырьё (табельный, raw_product) нельзя логировать на стороне коннектора — оно не должно

переживать момент приёма. Обезличивание — ответственность приёма, не источника.


Связанные статьи: 04 — Механизм сбора · 02 — ПДн и Vault.