Files
autotest/DOCS/api-create-flow.md
T
2026-07-27 22:05:19 +04:00

269 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ⚠️ LEGACY — НЕАКТУАЛЬНО. Исторический документ.
# Полный поток CREATE — рабочая схема (доказано curl 2026-07-24)
## Базовые константы
```bash
API="https://lk-api-gateway-test.ngcloud.ru/api/v1/svc"
TOKEN=$(tr -d '\n' < secrets/test.token)
UA="Mozilla/5.0"
CT="Content-Type: application/json"
```
## ⛔ Где работает curl, а где нет
| Источник | Работает? | Причина |
|----------|-----------|--------|
| Локальная машина (прокси) | ❌ | DDoS-Guard режет |
| ВМ 213 (5.172.178.213) | ✅ | Прямой доступ к API |
| Pod в кластере | ✅ | Внутренняя сеть |
**Решение:** все curl через `ssh naeel@5.172.178.213 "curl ..."`.
## Полный поток (5 шагов)
### Шаг 0: Узнать svcOperationId для create
```bash
curl -s --max-time 15 \
-H "Authorization: Bearer $TOKEN" \
-H "User-Agent: $UA" \
"$API/services/1" | jq '.svc.operations[] | select(.operation=="create") | .svcOperationId'
# → 18 (для dummy)
```
### Шаг 0b: Получить список параметров
```bash
curl -s --max-time 15 \
-H "Authorization: Bearer $TOKEN" \
-H "User-Agent: $UA" \
"$API/instanceOperations/default/18" | jq '.svcOperation.cfsParams[] | {svcOperationCfsParamId, svcOperationCfsParam, dataType, isRequired, defaultValue, valueList}'
```
### Шаг 1: Создать инстанс
```bash
RESP=$(curl -s --max-time 15 -i \
-H "Authorization: Bearer $TOKEN" \
-H "User-Agent: $UA" \
-H "Content-Type: application/json" \
-d '{"serviceId":1,"displayName":"my-test-'$(date +%H%M%S)'","descr":""}' \
"$API/instances")
INSTANCE_UID=$(echo "$RESP" | grep -i '^location:' | tr -d '\r' | sed 's|.*/||')
echo "instanceUid=$INSTANCE_UID"
```
**Ответ:** `HTTP/2 201`, тело пустое. UUID в заголовке `Location`.
**Важно:**
- `displayName` должен быть уникальным → добавляем timestamp
- `descr` обязательно (пустая строка ок)
- UUID в Location — **uppercase** (например `6528854D-A4EA-428C-9FA4-68E85FA9B3AC`)
### Шаг 2: Создать операцию
```bash
RESP=$(curl -s --max-time 15 -i \
-H "Authorization: Bearer $TOKEN" \
-H "User-Agent: $UA" \
-H "Content-Type: application/json" \
-d '{"instanceUid":"'$INSTANCE_UID'","operation":"create"}' \
"$API/instanceOperations")
OP_UID=$(echo "$RESP" | grep -i '^location:' | tr -d '\r' | sed 's|.*/||')
echo "opUid=$OP_UID"
```
**Ответ:** `HTTP/2 201`, тело: `{}`. UUID в `Location`.
### Шаг 3: Задать параметры (по одному на каждый)
```bash
# 5 обязательных параметров для dummy create:
# 242 — resourceRealm (string, required, default="dummy")
curl -s --max-time 10 -o /dev/null -w '%{http_code}' \
-H "Authorization: Bearer $TOKEN" -H "User-Agent: $UA" -H "Content-Type: application/json" \
-d '{"instanceOperationUid":"'$OP_UID'","svcOperationCfsParamId":242,"paramValue":"dummy"}' \
"$API/instanceOperationCfsParams"
# → 201
# 198 — durationMs (integer>=0, required, default="0")
curl -s --max-time 10 -o /dev/null -w '%{http_code}' \
-H "Authorization: Bearer $TOKEN" -H "User-Agent: $UA" -H "Content-Type: application/json" \
-d '{"instanceOperationUid":"'$OP_UID'","svcOperationCfsParamId":198,"paramValue":"0"}' \
"$API/instanceOperationCfsParams"
# → 201
# 199 — failAtStart (boolean, required, default="false")
curl -s --max-time 10 -o /dev/null -w '%{http_code}' \
-H "Authorization: Bearer $TOKEN" -H "User-Agent: $UA" -H "Content-Type: application/json" \
-d '{"instanceOperationUid":"'$OP_UID'","svcOperationCfsParamId":199,"paramValue":"false"}' \
"$API/instanceOperationCfsParams"
# → 201
# 200 — failInProgress (boolean, required, default="false")
curl -s --max-time 10 -o /dev/null -w '%{http_code}' \
-H "Authorization: Bearer $TOKEN" -H "User-Agent: $UA" -H "Content-Type: application/json" \
-d '{"instanceOperationUid":"'$OP_UID'","svcOperationCfsParamId":200,"paramValue":"false"}' \
"$API/instanceOperationCfsParams"
# → 201
# 863 — arr (array, required, valueList=["test","2","val1"])
# ⚠️ ВАЖНО: array параметры передаются как JSON-строка!
curl -s --max-time 10 -o /dev/null -w '%{http_code}' \
-H "Authorization: Bearer $TOKEN" -H "User-Agent: $UA" -H "Content-Type: application/json" \
-d '{"instanceOperationUid":"'$OP_UID'","svcOperationCfsParamId":863,"paramValue":"[\"test\"]"}' \
"$API/instanceOperationCfsParams"
# → 201
```
**Важно:**
- Порядок параметров **не важен**
- Все `paramValue`**строки** (даже числа и булевы)
- Array: `"[\"test\"]"`**JSON-строка**, не голый массив
- Map/map-fixed — **JSON-строка** вида `"{\"key\":\"value\"}"`
- Endpoint: `/instanceOperationCfsParams` (НЕ `/instanceOperations/{uid}/params` — такого нет!)
### Шаг 4: Запустить
```bash
curl -s --max-time 15 \
-H "Authorization: Bearer $TOKEN" \
-H "User-Agent: $UA" \
-H "Content-Type: application/json" \
-d '{}' \
"$API/instanceOperations/$OP_UID/run"
# → 201 (тело пустое)
```
**⚠️ БЕЗ /run НЕ РАБОТАЕТ!** HAR браузера показывает auto-start, но через API операция не стартует автоматически. `/run` обязателен.
### Шаг 5: Поллинг статуса
```bash
# Ждать пока operationIsInProgress == false и explainedStatus != "creating"
for i in $(seq 1 60); do
STATUS=$(curl -s --max-time 10 \
-H "Authorization: Bearer $TOKEN" \
-H "User-Agent: $UA" \
"$API/instances?pageSize=200&page=1")
FOUND=$(echo "$STATUS" | jq -r --arg uid "$INSTANCE_UID" \
'.results[] | select(.instanceUid == $uid) | "\(.explainedStatus) inProgress=\(.operationIsInProgress)"')
if [ -n "$FOUND" ]; then
echo "[$i] $FOUND"
if echo "$FOUND" | grep -qv "inProgress=True" && echo "$FOUND" | grep -qv "creating"; then
echo "ГОТОВО!"
break
fi
fi
sleep 5
done
```
## Параметры dummy create (svcOperationId=18)
| ID | Имя | Тип | Обязательный | По умолчанию | valueList |
|----|-----|-----|-------------|-------------|-----------|
| 242 | resourceRealm | string | ✅ | dummy | ["dummy"] |
| 198 | durationMs | integer>=0 | ✅ | 0 | — |
| 199 | failAtStart | boolean | ✅ | false | ["false","true"] |
| 200 | failInProgress | boolean | ✅ | false | ["false","true"] |
| 863 | arr | array | ✅ | — | ["test","2","val1"] |
| 201 | whereFail | integer>0 | ❌ | 1 | ["1","2","3"] |
| 286 | bodymessage | string | ❌ | — | — |
| 321 | mapExample | map | ❌ | — | — |
| 322 | jsonExample | json | ❌ | — | — |
| 396 | nestedRefExample | — | ❌ | — | [] |
| 647 | mapFixed | map-fixed | ❌ | — | — |
| 654 | arrayMapFixedExample | array-map-fixed | ❌ | — | — |
## ⛔ ВСЕ ОШИБКИ (хронология)
### Ошибка 0: DDoS-Guard блокирует curl с локальной машины
- **Симптом:** `403 Forbidden` / пустой ответ
- **Причина:** DDoS-Guard требует `User-Agent: Mozilla/5.0` и всё равно может резать
- **Решение:** curl через ВМ 213 (`ssh naeel@5.172.178.213 "curl ..."`)
### Ошибка 1: `'HttpClient' object has no attribute 'post'` (v1.0.7)
- **Причина:** В http_client.py был только `get()`
- **Исправление:** Добавлен `post()` метод
### Ошибка 2: `r.json()` на пустом ответе (v1.0.8)
- **Причина:** POST /instances → 201 с пустым телом, `r.json()` падает
- **Исправление:** try/except, возвращаем `{}`
### Ошибка 3: instanceUid не извлекался (v1.0.9)
- **Причина:** UUID в заголовке `Location`, не в теле ответа
- **Исправление:** Парсинг Location → UUID
### Ошибка 4: cfsParams в POST /instances (v1.0.10)
- **Симптом:** `400 Bad Request`
- **Причина:** Параметры нельзя передавать при создании инстанса
- **Исправление:** Убраны cfsParams из payload
### Ошибка 5: `descr` обязателен (v1.0.11)
- **Симптом:** `400 Bad Request`
- **Причина:** Поле `descr` required в POST /instances
- **Исправление:** `"descr": ""`
### Ошибка 6: displayName не уникален (v1.0.13)
- **Симптом:** `400 "Instance Display Name not unique"`
- **Причина:** Имя `autotest-1` уже занято
- **Исправление:** Timestamp в имени
### Ошибка 7: cfsParams в POST /instanceOperations (v1.0.23)
- **Симптом:** `422 "required CFS parameter failInProgress (200) is missing"`
- **Причина:** cfsParams нельзя передавать в /instanceOperations — они идут отдельно
- **Исправление:** Параметры через `/instanceOperationCfsParams`
### Ошибка 8: Неправильный endpoint для параметров (v1.0.24)
- **Симптом:** 404 / параметры не применяются
- **Причина:** Использовался `/instanceOperations/{uid}/params` (не существует)
- **Исправление:** Правильный endpoint: `/instanceOperationCfsParams`
### Ошибка 9: Пустые параметры очищали defaults (v1.0.26)
- **Симптом:** defaults не подставлялись
- **Причина:** Пустые paramValue перезаписывали default
- **Исправление:** Отправлять все 12 параметров (HAR analysis показал что так правильно)
### Ошибка 10: Auto-start не работает через API (v1.0.34→1.0.35)
- **Симптом:** Инстанс в статусе `not created` после всех шагов
- **Причина:** HAR показывает auto-start через UI, но через API нужен явный `/run`
- **Исправление:** Добавлен шаг 4 — `POST /instanceOperations/{opUid}/run`
- **Доказательство:** curl без /run → `not created`, curl с /run → `running`
### Ошибка 11: POST body = None → DDoS-Guard блокирует (v1.0.33)
- **Симптом:** Запрос отклонён
- **Причина:** `json=None` → тело пустое → DDoS-Guard режет
- **Исправление:** Всегда `json={}` минимум
### Ошибка 12: Array параметры как raw string (v1.0.31)
- **Симптом:** 400 / неверный формат
- **Причина:** `["test"]` — голый массив, а нужна JSON-строка
- **Исправление:** `"[\"test\"]"` — paramValue как экранированная JSON-строка
## Сводная таблица эндпоинтов CREATE
| Шаг | Метод | Путь | Payload | Ответ |
|-----|-------|------|---------|-------|
| 0 | GET | `/services/{svcId}` | — | `.svc.operations[]` |
| 0b | GET | `/instanceOperations/default/{svcOpId}` | — | `.svcOperation.cfsParams[]` |
| 1 | POST | `/instances` | `{serviceId, displayName, descr}` | 201, Location→instanceUid |
| 2 | POST | `/instanceOperations` | `{instanceUid, operation}` | 201, Location→opUid |
| 3 | POST | `/instanceOperationCfsParams` | `{instanceOperationUid, svcOperationCfsParamId, paramValue}` | 201 (×N) |
| 4 | POST | `/instanceOperations/{opUid}/run` | `{}` | 201 |
| 5 | GET | `/instances?pageSize=200` | — | Поллинг `explainedStatus` |
## Итог
- **Всего итераций:** 19 (v1.0.6 → v1.0.35)
- **Уникальных багов:** 12
- **Ключевой урок:** Всегда сверяться 1:1 с Go-клиентом, не гадать
- **Рабочий proof:** 2026-07-24 14:48, `curl-test-144834`, статус `running`