12 KiB
12 KiB
⚠️ LEGACY — НЕАКТУАЛЬНО. Исторический документ.
Полный поток CREATE — рабочая схема (доказано curl 2026-07-24)
Базовые константы
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
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: Получить список параметров
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: Создать инстанс
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должен быть уникальным → добавляем timestampdescrобязательно (пустая строка ок)- UUID в Location — uppercase (например
6528854D-A4EA-428C-9FA4-68E85FA9B3AC)
Шаг 2: Создать операцию
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: Задать параметры (по одному на каждый)
# 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: Запустить
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: Поллинг статуса
# Ждать пока 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 - Причина: Поле
descrrequired в 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