# Полная логика операций — из 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=...) ```