Перейти к содержимому

Расширение Soul Stack

Базовый набор core-модулей покрывает типовые операции — пакеты, файлы, сервисы, пользователи, cron, монтирование и так далее. Когда нужной интеграции в нём нет, Soul Stack расширяется плагинами — отдельными исполняемыми файлами, которые подключаются к системе по единому протоколу, без модификации ядра.

Это тот же путь к паритету с экосистемами зрелых инструментов: core-набор — нативный Go-код, а нишевые и специфичные для организации интеграции пишутся как плагины через публичный Go SDK. SDK и плагины — под Apache 2.0; свой модуль вы вправе публиковать под любой лицензией, включая проприетарную. Ядро при этом под BSL 1.1 (fair-code), но плагинов это не касается: они отдельные процессы через gRPC, а не производная работа ядра.

Core-модульПлагин
Где живётстатически встроен в исполняемый файл soul / keeperотдельный исполняемый файл
Установкане нужна, версия = версия сборкипоставляется как самостоятельный артефакт
Кто пишетпоставляется с Soul Stackвы, ваша организация или сообщество
ЯзыкGo (в ядре)любой язык с gRPC; Go SDK — готовый
Изоляцияв адресном пространстве host-процессаотдельный процесс, gRPC через сокет

Каталог встроенных модулей — Модули. Этот раздел — про то, как добавить своё.

Плагин — это отдельный исполняемый файл, который host-процесс (soul или keeper) запускает как дочерний процесс (sub-process) на время операции. Общение идёт не через stdin/stdout-парсинг, а по gRPC через Unix domain socket:

  1. Host запускает исполняемый файл-плагин как дочерний процесс и передаёт ему путь к сокету через переменную окружения.
  2. Плагин при старте пишет в stdout одну строку handshake — JSON с магическим полем-маркером, версией протокола и адресом сокета. Все строки до неё host игнорирует (защита от случайного вывода в init() или из библиотек).
  3. Дальше host и плагин общаются по gRPC поверх этого сокета.
  4. По завершении операции host штатно гасит плагин сигналом (graceful shutdown с grace-периодом).

Lifecycle — one-shot: плагин поднимается на операцию и завершается после неё. Это та же модель «one-line handshake → gRPC-over-socket», что у Terraform-провайдеров и Vault-плагинов (идея, а не код: библиотека hashicorp/go-plugin в зависимости не тянется, формат свой).

Сокет — файл с правами 0700, владелец — служебный пользователь host-процесса; лежит в host-managed директории. Защита канала — на уровне прав файловой системы: чужой процесс физически не откроет сокет. TLS на plugin-сокете не используется — для Unix-сокета с правами 0700 он не даёт выигрыша.

Инфраструктура для всех трёх типов единая — один и тот же handshake, способ запуска, формат манифеста и версионирование. Различается только gRPC-контракт (набор методов), который плагин реализует, и кто его запускает.

Тип (kind)Исполняемый файлHostЧто делает
SoulModulesoul-mod-<имя>soul-агент (на хосте)Реализует шаг Destiny: приводит ресурс к состоянию (Validate / Apply, идемпотентно).
CloudDriversoul-cloud-<провайдер>keeper (на сервере)Создаёт / удаляет / опрашивает VM у облачного провайдера.
SshProvidersoul-ssh-<провайдер>keeper (на сервере)Поставляет SSH-credentials для push-режима.

Имя исполняемого файла (soul-mod-* / soul-cloud-* / soul-ssh-*) — соглашение, а тип плагина определяется полем kind в его манифесте.

Плагины пишутся на Go через публичный SDK. Он закрывает всю механику протокола, чтобы автор плагина писал только бизнес-логику:

  • handshake-helper — читает путь к сокету, пишет handshake-строку, поднимает gRPC-сервер, обрабатывает сигнал завершения;
  • типизированные интерфейсы для каждого из трёх контрактов (SoulModule / CloudDriver / SshProvider);
  • типы манифеста плагина.

Зависимость минимальна: автор плагина подключает только модули SDK и контрактов плагинов — без кода Keeper-а или Soul-агента. Подробнее про сборку и интерфейс — в Как написать SoulModule.

Каркас нового SoulModule-плагина генерируется командой soul-lint plugin-init — это даёт готовое дерево проекта, остаётся написать Apply.

Рядом с исполняемым файлом — статический manifest.yaml. Он описывает плагин без его запуска: тип (kind), версию протокола, имя, поддерживаемые состояния и их параметры, требуемые от host-а возможности (required_capabilities) и затрагиваемые ресурсы (side_effects).

Манифест читает soul-lint при статической проверке Destiny — ловит неизвестный модуль, неизвестное состояние, неверные параметры и нехватку прав до применения на хостах, не поднимая плагин-процесс. Формат манифеста подробнее — в Как написать SoulModule.