92 lines
8.2 KiB
Markdown
92 lines
8.2 KiB
Markdown
# Паттерн создания ресурсов "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 (create‑params) с `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` приведёт к росту расходов.
|