Files
tf_provider/docs/20_discovery/resource-creation-pattern.md
T
2026-06-30 15:45:24 +04:00

8.2 KiB
Raw Blame History

Паттерн создания ресурсов "Tubulus" (Platinum Standard)

В платформе Nubes Cloud большинство ресурсов (VDC, S3, DBaaS, Tubulus-болванки) подчиняются строгому 7-шаговому циклу создания. Простого POST /instances недостаточно — ресурс появится в UI, но останется в статусе "not created", пока не будет выполнен финальный POST /run.

Пошаговый алгоритм

Шаг 1: Инициализация (Create Instance)

Отправляем POST /instances.

  • Payload: contractId, serviceId, specificationItemId, displayName.
  • Результат: Получаем instanceUid.

Шаг 2: Создание операции (Create Operation)

Отправляем POST /instanceOperations для привязки операции создания к инстансу.

  • Payload: instanceUid, operation: "create".
  • Результат: Получаем instanceOperationUid.

Шаг 3: Получение параметров (Fetch Parameters)

Отправляем GET /instanceOperations/{uid}?fields=cfsParams.

  • Цель: Получить список параметров (svcOperationCfsParamId), которые платформа ожидает для этого ресурса.

Шаг 4: Отправка параметров (Submit Parameters) — Критично!

Для каждого параметра из списка (даже если он пустой или имеет значение по умолчанию) нужно отправить POST /instanceOperationCfsParams.

  • Payload: instanceOperationUid, svcOperationCfsParamId, paramValue.
  • Важно: Браузер всегда переотправляет все параметры. Пропуск этого шага может привести к ошибкам валидации.

Шаг 5: Валидация (Validate)

Отправляем GET /instanceOperations/{uid}/validate-cfs.

  • Проверяем, что ответ 200 OK и нет ошибок в теле ответа.

Шаг 6: Запуск (Run) — Самый важный шаг!

Отправляем POST /instanceOperations/{uid}/run.

  • Payload: Обязательно {} (пустой JSON-объект). НЕ nil, а именно {}.
  • Результат: После этого шага бэкенд начинает реальную работу (например, вызывает Jenkins или Ansible).

Шаг 7: Ожидание готовности (Polling)

Периодически опрашиваем GET /instances/{uid}.

  • Ждем, когда explainedStatus станет running (для S3) или Active.

Специфика S3 бакетов (nubes_s3_bucket)

  1. Модификация (Update): В текущем UI и API отсутствует операция modify. Ресурс S3 является иммутабельным в плане параметров бакета через этот API. Для изменения (например, размера) требуется пересоздание или использование других API (если они будут найдены).
  2. Удаление (Delete): Выполняется через стандартный DELETE /instances/{id}.
  3. Уникальность: displayName и bucket_name должны быть уникальны в рамках контракта/платформы. Рекомендуется использовать суффиксы с временной меткой в тестах.
  4. Placement: Допустимые значения: HOT (по умолчанию) или COLD.

Рекомендации для разработчика провайдера

  • Объединяйте шаги 1-6 в одну функцию клиента (например, CreateInstance в client_impl.go).
  • Всегда передавайте пустую карту map[string]interface{}{} в метод Run, чтобы она сериализовалась в {}.
  • Тщательно логируйте instanceOperationUid, так как по нему можно отследить ошибки в логах платформы.

Troubleshooting

  • Висит в "not created": Вы забыли вызвать Шаг 6 (Run) или отправили неверный payload.
  • Ошибка 400 на параметрах: Проверьте, что все ID параметров соответствуют результату из Шага 3.

Operation Lifecycle & Success Criteria (Official Developer Info)

Операции в Nubes Cloud выполняются асинхронно.

  • 201 Created: Операция запущена успешно.
  • Polling (GET status): Каждый запрос статуса возвращает 200 OK. Это означает, что платформа успешно обрабатывает запрос состояния, но не гарантирует успех самой операции.
  • Completion Timestamp: Операция считается завершенной только тогда, когда в ответе появляется временная метка завершения.
  • isSuccessful: Ключевой флаг, который определяет успех операции и отрисовывает "зелёную галочку" в интерфейсе. Если операция завершена, но isSuccessful: false, ресурс может находиться в неконсистентном состоянии.

Suspend/Resume и совпадение параметров (Discovery Notes)

Контекст: в Nubes Cloud многие сервисы не удаляются напрямую. destroy приводит к suspend и двухнедельному карантину. Это означает, что следующий apply может столкнуться с существующим инстансом в suspend.

Принцип восстановления

Если найден suspended инстанс с тем же resource_name, корректное поведение:

  1. Сравнить параметры в Terraform (createparams) с instance.state.params.
  2. Resume выполнять только при полном совпадении параметров.
  3. При несовпадении — вернуть стандартную ошибку "resource already exists".

Потенциальные мины

  • Несовпадение ключей: state.params может использовать ключи, отличные от code в YAML — сравнение даст false.
  • Типы/форматы: bool/int/JSON/масивы могут быть сериализованы по‑разному (строка vs JSON).
  • Defaults: если параметр не задан в TF и приходит default от API, возможны ложные mismatches.
  • RefSvcId: в create могут отправляться UUID, а в state.params может быть имя — mismatch.
  • Ручные изменения: любые правки вне TF делают resume невозможным.
  • Пустые params: если API не возвращает state.params, сравнение всегда провалится.
  • YAML/Go рассинхрон: неверный маппинг ID→code приводит к ложным mismatch.
  • Сеть/таймауты: дополнительный GET /instances/{id} может фейлиться и блокировать resume.

Экономический аспект

suspend сохраняет данные и продолжает потреблять дисковое пространство — пользователь продолжает платить. Регулярное создание новых инстансов вместо восстановления suspended приведёт к росту расходов.