core.soul
Регистрация Soul-а по SID в реестре Keeper-а и привязка к стабильным Coven-меткам.
core.soul.registered привязывает Soul (по SID) к набору стабильных Coven-меток в реестрах Keeper-а (Postgres souls + coven) — шаг исполняется на самом Keeper-е, диспетчер on: keeper обязателен (иначе ошибка валидации scenario). Идемпотентен по конструкции: changed=true только если запись была создана модулем или итоговый набор coven изменился (порядок-независимая сверка). Принимает одиночный SID или список (через CEL register.<step>.hosts) и опционально несёт блокирующий барьер онбординга await_online; bootstrap-токены и SoulSeed модуль не выписывает — это компетенция онбординга.
Требования
- Rootне требуется
- Сторона
keeper-side - Коллекция
soulstack.orchestration - Категория
orchestration
Состояния
core.soul.registered — Soul с указанным sid находится в реестре Keeper-а и привязан к набору Coven-меток (по mode); опционально несёт барьер онбординга await_online.
Запись souls была создана модулем, либо итоговый набор coven отличается от текущего (порядок-независимая сверка).
Запись souls уже была и набор coven совпал.
Параметры
| Параметр | Тип | Обяз. / дефолт | Описание |
|---|---|---|---|
sid | string | required | SID (FQDN) целевого Soul: одиночная строка ИЛИ список (через CEL `${ register.<step>.hosts }`) — регистрация N хостов одним шагом-барьером, ADR-061. |
coven | list<string> | required | Набор Coven-меток (kebab-case), применяется ко всем SID. |
mode | string | optional | append (default) | replace | remove. |
refresh_soulprint | bool | optional | Mid-run re-resolve roster прогона (ADR-061; стратификация/re-resolve — слайсы S2/S3, echo refreshed:false). |
await_online | bool | optional | Барьер онбординга (ADR-061): после регистрации блокирующе ждать, пока созданные Souls станут online (Redis SID-lease). |
await_timeout | stringformat: duration | optional | Верхняя граница ожидания барьера. ОБЯЗАТЕЛЕН при await_online: true. Потолок — keeper.yml::max_await_timeout. |
await_min_count | int | optional | Минимум online-хостов для успеха барьера. Default — число регистрируемых SID (все). |
await_poll_interval | stringformat: duration | optional | Период опроса presence (default ~2s). |
Пример — Привязать нового Soul к корневому coven инкарнации (append по умолчанию)
- name: Bind new replica to the incarnation root coven on: keeper module: core.soul.registered params: sid: "${ vars.new_sid }" coven: ["${ incarnation.name }"]Пример — Регистрация списка созданных VM с барьером онбординга (ADR-061)
- name: Register provisioned shards and await onboarding on: keeper module: core.soul.registered register: shards params: sid: "${ register.provision.hosts }" coven: ["${ incarnation.name }"] await_online: true await_timeout: 10mOutput
| Поле | Тип | Описание |
|---|---|---|
sid | string | array<string> | эхо входа: строка при одиночном sid, массив при списочном |
coven | array<string> | итоговый набор coven после применения mode (не переданный аргумент) |
mode | string | применённый mode |
created | bool | true, если хотя бы одна запись souls была создана модулем |
refreshed | bool | эхо refresh_soulprint |
removed | array<string> | только при mode: remove: фактически снятые метки |
online | array<string> | только при await_online: SID, ставшие online к моменту успеха/таймаута |
pending | array<string> | только при await_online: SID, не успевшие online к таймауту (диагностика B1-strict) |
satisfied | bool | только при await_online: достигнут ли await_min_count |
Справочник
Семантика mode
Стратегия применения переданного набора coven к уже привязанным меткам хоста.
| mode | Итоговый набор coven | Поведение по краям |
|---|---|---|
| append (default) | существующие ∪ переданные | повтор с тем же набором — no-op (changed=false) |
| replace | только переданные (не упомянутые удаляются) | пустой coven: [] — ошибка (хост обязан сохранить хотя бы одну метку) |
| remove | существующие без переданных | метки, которых нет на хосте, — пропускаются без ошибки |
Заметки
- Keeper-side, не трогает хост: все side-effect-ы — в реестрах Keeper-а (Postgres souls + coven), а не в файловой системе или процессах Soul-а. Манифеста required_capabilities у модуля нет — это keeper-internal операция над Postgres, а root/capability хоста здесь неприменимы (доступ — keeper-разрешение оператора, см. secure_defaults).
- Если записи souls для SID ещё нет — модуль создаёт её под status: pending (transport: agent, пустой coven, CreatedByAID/LastSeenAt = null): новый хост из сценария или хост после cloud-create. Bootstrap-токены и SoulSeed не выписывает.
- list-SID: sid принимает строку ИЛИ список. Целевой случай — один create-scenario создаёт N VM (их sid приходят списком в register.<provision>.hosts из core.cloud.created), а этот шаг регистрирует их и (с await_online) ждёт онбординга одним барьером; переданный coven применяется к каждому SID. Литеральный список sid: [a, b] статически не проходит soul-lint (manifest объявляет type: string) — список всегда приходит CEL-выражением register.*. Форма output по входу: одиночный sid → строкой, список → массивом.
- Барьер онбординга await_online: после регистрации всех SID шаг блокирующе поллит presence (период await_poll_interval, default ~2s) под общим await_timeout, пока готовых хостов не станет ≥ await_min_count (default — все SID). Источник online — Redis SID-lease (живой EventStream), не PG souls.status. await_timeout обязателен при await_online: true и ограничен сверху keeper.yml::max_await_timeout. Недобор кворума к таймауту → шаг failed → fail-stop прогона (B1-strict). await_online без сконфигурированного presence-checker-а на keeper-е → failed (молчаливый success недопустим).
- refresh_soulprint (ADR-061, S2/S3): true делает шаг границей стратификации — после его успеха scenario-runner пере-резолвит roster прогона перед следующим Passage (live-снимок), output refreshed эхает флаг. Вместе с await_online ужесточает барьер до facts-wait: SID готов = online И typed soulprint записан в PG (souls.soulprint_facts IS NOT NULL) — снимает гонку render_failed на provision-from-zero.
Безопасность и умолчания
- Keeper-side, не Soul-side: шаг исполняется в процессе Keeper-а (диспетчер on: keeper), а не soul-агентом на хосте, поэтому root/capability-семантика неприменима. Доступ к запуску такого scenario регулируется RBAC оператора на уровне прогона (keeper-разрешение); сам core-модуль отдельного permission не объявляет, а создаваемая запись souls пишется с CreatedByAID: null (keeper-internal action).
- Валидация входа против инъекции мусора в реестр: sid проверяется как FQDN (keepersoul.ValidSID), каждая метка coven — как kebab-case 1..63 (keepersoul.ValidCoven); невалидное — шаг падает и в реестр не попадает. Симметрично API-границе POST /v1/souls, чтобы scenario-путь не был чёрным ходом в обход проверок.
- Footgun-защита mode: replace: пустой coven: [] отвергается ошибкой — хост обязан сохранить хотя бы одну Coven-метку, иначе потерял бы корневой coven инкарнации и выпал из таргетинга.
- Не выписывает bootstrap-токены и SoulSeed — секретов модуль не производит и не раскрывает; выдача bootstrap-креденшелов остаётся компетенцией онбординга.
- DoS-guard барьера онбординга: await_timeout ограничен сверху оператор-потолком keeper.yml::max_await_timeout (default 30m, fail-closed) — шаг с завышенным await_timeout отвергается failed ДО опроса, а не тихо обрезается, чтобы ошибочный await_timeout не держал run-goroutine/Acolyte-воркер занятым.