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

core.cloud

← Каталог модулей

keeper-sidesoulstack.cloudcloud

Создание, удаление и расширение облачных VM через CloudDriver-плагин провайдера.

core.cloud создаёт, удаляет и расширяет облачные VM, вызывая CloudDriver-плагин провайдера (soul-cloud-<provider>) через PluginHost (gRPC-over-stdio). Шаг исполняется на самом Keeper-е, диспетчер on: keeper обязателен (иначе ошибка валидации scenario): side-effect-ы — у провайдера (реальный биллинг) и в Postgres-реестрах Keeper-а, файловую систему хоста модуль не трогает. created не идемпотентен (повтор создаёт новые VM), destroyed каскадно обновляет реестры после успешного удаления, resized может вызвать downtime. SID создаваемого хоста = FQDN, который вернул провайдер.

Требования

  • Rootне требуется
  • Сторонаkeeper-side
  • Коллекцияsoulstack.cloud
  • Категорияcloud

Состояния

core.cloud.created — Запросить у провайдера count VM: на каждую — запись в реестре souls (status: pending) и bootstrap-токен.

Меняется, когда

Всегда: cloud-create императивен и не идемпотентен на уровне модуля — повтор создаёт новые VM.

Не меняется, когда

Никогда — операция всегда выполняется.

Параметры

ПараметрТипОбяз. / дефолтОписание
providerstringrequiredИмя cloud-Provider в реестре (driver + креды + регион).
profilemapoptionalПараметры VM-профиля (backend-специфично).
countintoptionalСколько VM создать (default 1, >= 1).
userdatastringoptionalCloud-init userdata (взаимоисключим с generate_userdata и self_onboard).
generate_userdatabooloptionalСгенерировать userdata из keeper.yml cloud_init (ADR-017(h)).
namestringoptionalБазовое имя VM-батча (self-onboard Вариант T): keeper предсказывает FQDN=<name>-<index>.<suffix>. Обязателен при self_onboard.
self_onboardbooloptionalVM онбордится сама из cloud-init (Вариант T, ADR-017(h)): keeper предсказывает FQDN и запекает per-VM токены в userdata. Требует name + providers.fqdn_suffix.

Пример — Создать VM через драйвер (spawn опционален через when:-guard)

- name: provision
on: keeper
when: has(input.spawn)
module: core.cloud.created
params:
provider: "${ input.spawn.provider }"
profile: "${ input.spawn.profile }"
count: "${ input.spawn.count }"

Output

ПолеТипОписание
hostsarray<object>по записи на VM: {sid, vm_id, primary_ip, attributes?, bootstrap_token}
countnumberчисло созданных VM
vm_idsarray<string>provider-side ID созданных VM
actioncreated

Справочник

Регистрация Cloud-Provider и Cloud-Profile

Чтобы scenario мог сослаться на provider и profile, их сначала регистрируют в реестрах Keeper-а через Operator API (REST / MCP / web-UI) — это runtime-данные в PostgreSQL, не git.

РеестрRESTPermissionAudit
Cloud-ProviderGET · POST /v1/providers · GET · DELETE /v1/providers/{name}provider.read · provider.create · provider.deleteprovider.created / provider.deleted
Cloud-ProfileGET · POST /v1/profiles · GET · DELETE /v1/profiles/{name}profile.read · profile.create · profile.deleteprofile.created / profile.deleted

Заметки

  • Keeper-side, не трогает хост: side-effect-ы — у cloud-провайдера и в реестрах Keeper-а (Postgres), а не на Soul-хосте. Манифеста required_capabilities у модуля нет — это keeper-internal операция, root/capability хоста неприменимы (доступ — keeper-разрешение оператора, см. secure_defaults).
  • created не идемпотентен по конструкции (changed=true всегда): повтор шага создаёт НОВЫЕ VM, а не сверяется с существующими. Это реальный биллинговый side-effect — управляйте повтором guard-ом на уровне scenario (when: / changed_when:), не полагаясь на идемпотентность модуля.
  • destroyed — деструктивная cascade: PluginHost.Destroy(vm_ids) физически уничтожает инстансы; затем (при непустом sids) одна PG-транзакция переводит souls → destroyed, активные soul_seeds → orphaned, bootstrap_tokens → burned. Cascade выполняется ПОСЛЕ успешного cloud-destroy — при провале destroy реестры остаются нетронутыми (хост ещё жив у провайдера).
  • resized может вызвать downtime: драйвер сам решает, нужен ли stop/start VM ради расширения (Keeper к последовательности агностичен), в output поле caused_downtime на каждую VM сигналит перезагрузку. Реестр souls не трогается (resize не меняет состав душ). Драйвер без Resizable-capability → resize.unsupported.
  • SID создаваемого хоста = FQDN, который вернул провайдер (VmInfo.fqdn); VM без fqdn — шаг падает, такую VM нельзя использовать как SID.
  • Provider — учётка облака (имя, тип драйвера, credentials_ref = vault-путь; секрет в реестре не резолвится и не хранится в открытом виде). Profile — VM-spec поверх Provider-а (образ, сеть, размер). Удаление Provider с зависимыми Profile-ями → 409 (FK RESTRICT); POST Profile с несуществующим provider → 422.

Безопасность и умолчания

  • Keeper-side, не Soul-side: шаг исполняется в процессе Keeper-а (on: keeper), side-effect-ы — у провайдера и в Postgres-реестрах, не на хосте, поэтому root/capability-семантика неприменима. Запуск такого scenario регулируется RBAC оператора (keeper-разрешение); создаваемые записи souls пишутся с CreatedByAID: null (keeper-internal action).
  • Реальный финансовый side-effect (created): шаг создаёт настоящие VM у провайдера — это биллинг, и он не идемпотентен (повтор создаёт новые VM, а не сверяется с существующими). Управляйте повтором guard-ом на уровне scenario, не полагаясь на идемпотентность модуля.
  • destroyed — деструктивная cascade-операция: физически уничтожает инстансы, затем переводит записи реестров в финальные состояния. Связку sid↔vm_id держит caller — ошибка в ней приведёт к destroy не той VM, поэтому источник vm_ids/sids должен быть доверенным.
  • Plain bootstrap-token в register-output (created): hosts[].bootstrap_token — plain одноразовый токен, намеренно в output, потому что cloud-init flow обязан передать его на VM при первичной загрузке (единственный момент, когда plain-токен виден; в БД — только hash, восстановить нельзя). Секретность держит substring-фильтр audit.MaskSecrets (фрагмент token) на ВСЕХ каналах вывода; переименовывать ключ bootstrap_token без проверки фильтра нельзя — иначе one-time token leak.
  • Обязательный audit-event cloud.provisioned пишется для всех state-ов; audit-фейл ВАЛИТ шаг (compliance-инвариант — деструктивная/биллинговая операция не должна пройти молча). В audit-payload — provider / vm_ids / sids / cascade-счётчики, но НЕ plain-токены.

См. также