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