Docs: full operation logic from Terraform provider (VM)

This commit is contained in:
2026-07-26 11:21:11 +04:00
parent a82e08d23b
commit 170377b43c
+201
View File
@@ -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 <TOKEN>
```
### 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=...)
```