diff --git a/DOCS/terraform-operations-full-logic.md b/DOCS/terraform-operations-full-logic.md new file mode 100644 index 0000000..b82b236 --- /dev/null +++ b/DOCS/terraform-operations-full-logic.md @@ -0,0 +1,201 @@ +# Полная логика операций — из Terraform-провайдера (ВМ) + +> Источник: `/home/naeel/tf_provider/provider/internal/core/client.go` (1581 строка) +> Скопировано с ВМ 5.172.178.213, 2026-07-26 + +--- + +## HTTP-клиент (`doRequest`) + +### Заголовки +``` +User-Agent: Mozilla/5.0 +Accept: */* +Content-Type: application/json (для POST/PUT/PATCH) +Authorization: Bearer +``` + +### Retry +- До 3 попыток (2s, 4s, 8s задержка) +- Только для GET и только на 429/503/502/504/401 +- POST/PUT/PATCH: `req.Close = true` (новое TCP-соединение, DDoS-Guard) + +### URL +- Legacy proxy: `{endpoint}?endpoint=/instances&page=1` +- Новый REST: `{endpoint}/instances?page=1` + +--- + +## CREATE (`CreateGenericInstanceUniversalV6`) + +``` +serviceId, displayName, params map[int]string → instanceUid +``` + +### Шаги + +| # | Метод | Путь | Тело | Ответ | +|---|-------|------|------|-------| +| 1 | POST | `/instances` | `{serviceId, displayName, descr}` | Location → instanceUid | +| 2 | POST | `/instanceOperations` | `{instanceUid, operation:"create"}` | Location → opUid | +| 3 | GET | `/instanceOperations/{opUid}?fields=cfsParams` | — | `cfsParams[]` (полные параметры с defaults) | +| 4 | — | resolveRefSvcParamValues | — | резолв refSvc-параметров | +| 5 | POST | `/instanceOperationCfsParams` | `{instanceOperationUid, svcOperationCfsParamId, paramValue}` | 201 (×N — все params из вызова) | +| 6 | POST | `/instanceOperationCfsParams` | то же для **required** параметров с **defaultValue** (которые не были в params) | 201 (×M) | +| 7 | GET | `/instanceOperations/{opUid}/validate-cfs` | — | валидация | +| 8 | POST | `/instanceOperations/{opUid}/run` | `{}` | запуск | +| 9 | GET | `/instanceOperations/{opUid}?fields=dtFinish,...` | — | поллинг до dtFinish | +| 10 | — | `ensureInstanceCreated` | — | проверка что инстанс создан | + +### Важно +- Параметры из вызова отправляются **первыми** +- Затем **required + defaultValue** (те что не были в вызове, но обязательны) +- `/validate-cfs` — отдельный шаг +- `/run` — обязателен +- **Критерий завершения: `dtFinish != nil && dtFinish != ""`** (НЕ `isInProgress`) + +--- + +## MODIFY / SUSPEND / DELETE / RESUME (`RunInstanceOperationUniversal`) + +``` +instanceUid, action, params → ok/error +``` + +### Шаги + +| # | Метод | Путь | Тело | Примечание | +|---|-------|------|------|------------| +| 1 | GET | `/instances` | — | Получить `availableOperations[]` и `svcOperationId` для action | +| 2 | — | `waitForInstanceIdle` | — | Если `operationIsPending || operationIsInProgress` — ждать | +| 3 | POST | `/instanceOperations` | `{instanceUid, svcOperationId, operation}` | **ВАЖНО: svcOperationId обязателен** | +| 4 | POST | `/instanceOperationCfsParams` | `{instanceOperationUid, svcOperationCfsParamId, paramValue}` | Для каждого параметра (если есть) | +| 5 | POST | `/instanceOperations/{opUid}/run` | `{}` | **ЗАПУСК** | +| 6 | GET | `/instanceOperations/{opUid}?fields=dtFinish,...` | — | Поллинг до dtFinish | + +--- + +## REDEPLOY (`RunRedeployOperation`) + +``` +instanceUid, timeoutOverride → ok/error +``` + +| # | Метод | Путь | Тело | Примечание | +|---|-------|------|------|------------| +| 1 | GET | `/instances` | — | Получить `availableOperations` | +| 2 | — | `waitForInstanceIdle` | — | Ждать idle | +| 3 | POST | `/instanceOperations` | `{instanceUid, svcOperationId, operation:"redeploy"}` | — | +| 4 | POST | `/instanceOperations/{opUid}/run` | `{}` | **СРАЗУ /run, без параметров** | +| 5 | GET | `/instanceOperations/{opUid}?fields=dtFinish,...` | — | Поллинг | + +--- + +## Ожидание завершения (`waitForOperationFinish`) + +``` +opUid, timeout → ok/error +``` + +### Поллинг (каждые 5 сек) + +Эндпоинт: `GET /instanceOperations/{opUid}?fields=dtFinish,isSuccessful,errorLog,isInProgress,isPending,duration,stages` + +Ответ: +```json +{ + "instanceOperation": { + "dtFinish": "2026-07-24T15:22:20...", + "isSuccessful": true, + "errorLog": null, + "isInProgress": false, + "isPending": false, + "duration": 27.89, + "stages": [...] + } +} +``` + +### Критерий завершения + +```go +if status.InstanceOperation.DtFinish != nil && strings.TrimSpace(*status.InstanceOperation.DtFinish) != "" { + // операция завершена + if !isSuccessful → ошибка (errorLog) + else → OK +} +``` + +**НЕ `isInProgress == false`**, a **`dtFinish != nil && dtFinish != ""`**. + +### Стадии + +Поле `stages[]` содержит: +- `instanceOperationStageUid` — UUID +- `stage` — название этапа +- `isSuccessful` — true/false +- `dtStart` / `dtFinish` — время +- `duration` — длительность в секундах +- `stageMsg` — JSON-строка `[["имя","текст"],...]` + +--- + +## Ожидание простоя (`waitForInstanceIdle`) + +```go +for { + state := GetInstanceState(instanceUid) + if !state.OperationIsPending && !state.OperationIsInProgress { + return nil // готов + } + sleep(5s) +} +``` + +--- + +## GetInstanceState + +Эндпоинт: `GET /instances?pageSize=200&page=N` (пагинация) + +Ищет instanceUid в результатах. Возвращает: + +```go +type InstanceStateResponse struct { + InstanceUid string + ServiceId int + ExplainedStatus string + IsDeleted bool + OperationIsInProgress bool + OperationIsPending bool + AvailableOperations []ApiOperation // {SvcOperationId, Operation} +} +``` + +--- + +## СВОДКА: обязательные поля в /instanceOperations + +| Операция | Поля | +|----------|------| +| create | `{instanceUid, operation}` | +| modify | `{instanceUid, svcOperationId, operation}` | +| suspend | `{instanceUid, svcOperationId, operation}` | +| delete | `{instanceUid, svcOperationId, operation}` | +| resume | `{instanceUid, svcOperationId, operation}` | +| redeploy | `{instanceUid, svcOperationId, operation}` | + +**Не-create операции требуют `svcOperationId`!** + +--- + +## СВОДКА: последовательность для не-create + +``` +1. GetInstanceState → svcOperationId для нужного action +2. waitForInstanceIdle +3. POST /instanceOperations {instanceUid, svcOperationId, operation} → opUid +4. POST /instanceOperationCfsParams {instanceOperationUid, svcOperationCfsParamId, paramValue} (×N, если есть params) +5. POST /instanceOperations/{opUid}/run {} +6. waitForOperationFinish (поллинг /instanceOperations/{opUid}?fields=...) +```