- Added DEV_STAND/FullPipe with modular configuration for vc_vdc resource creation:
- versions.tf: Terraform >= 1.5.0, provider nubes 2.0.1
- provider.tf: nubes provider config with DEV gateway endpoint
- variables.tf: variables for vdc (cpu=8, mem=32, guaranteed=0, fast storage=200GB)
- vdc.tf: nubes_vc_vdc resource definition supporting org name or UUID
- outputs.tf: vdc_id, vdc_name, vdc_state_params
- terraform.tfvars.example: example values without secrets
- Added docs/DEBUG_REPORT_VC_VDC_500.md documenting API 500 issue in Lucee backend:
- Error: getResourceRealmConfig fails casting Struct to string on GET /instanceOperations/{opUid}?fields=cfsParams
- Planned changes in provider/internal/core/client.go:
Implement graceful fallback in createInstanceWithContext to skip hard-failing
when GET ?fields=cfsParams returns 500, since vc_vdc ref parameters (organization_uid)
are already resolved to UUID and remaining parameters are literals/numbers.
5.6 KiB
5.6 KiB
Отчет о проблеме: Ошибка 500 при получении cfsParams для vc_vdc и план исправления
1. Проблема
При создании виртуального дата-центра nubes_vc_vdc (сервис 21 vc_vdc, операция создания 9) Terraform завершается с ошибкой клиента:
не удалось получить детали операции: ошибка API 500: Invalid call of the function [getResourceRealmConfig], first Argument [resourceRealm] is of invalid type, Cannot cast Object type [Struct] to a value of type [string]: the function is located at [/app/api/v1/resources/instance_operation_cfs_param.cfc]
2. Анализ причины
-
Место падения в провайдере:
provider/internal/core/client.go(строка 272 вcreateInstanceWithContext):opDetailsResp, _, err := c.doRequest(ctx, "GET", fmt.Sprintf("/instanceOperations/%s?fields=cfsParams", opUid), nil) if err != nil { return "", fmt.Errorf("не удалось получить детали операции: %w", err) } -
Поведение бэкенда Nubes (Lucee/ColdFusion):
- В файле
/app/api/v1/resources/instance_operation_cfs_param.cfcпри обработке запроса?fields=cfsParamsдля операции 9 вызывается функцияgetResourceRealmConfig(resourceRealm). - Для сервиса
vc_vdcполеresourceRealmв БД DEV-окружения хранится как комплексный объект (Struct), а не скалярная строка (string). - При попытке приведения типа
Struct -> stringбэкенд падает с HTTP 500.
- В файле
-
Сравнение с веб-интерфейсом (HAR/vdc.har):
- В официальном веб-интерфейсе ЛК запрос
GET /instanceOperations/{opUid}?fields=cfsParamsвообще не выполняется. - Браузер выполняет строго следующий флоу:
POST /instanceOperations-> получаетinstanceOperationUidPOST /instanceOperationCfsParams-> отправляет каждое значение CFS-параметраGET /instanceOperations/{opUid}/validate-cfs-> валидация бэкендомPOST /instanceOperations/{opUid}/run-> запуск операции в оркестраторе- Polling
GET /instanceOperations/{opUid}-> ожидание статуса завершения
- В официальном веб-интерфейсе ЛК запрос
-
Зачем провайдер делает шаг 2:
- Шаг 2 в провайдере использовался исключительно для вызова
resolveRefSvcParamValues(ctx, opDetails.InstanceOperation.CfsParams, params)— чтобы узнатьrefSvcIdпараметров и попробовать отрезолвить имена в UUID. - Для ресурса
nubes_vc_vdcпараметрorganization_uid(CFS param 30, refSvc 19) уже гарантированно отрезолвлен в UUID до создания операции (на этапеModifyPlanи в началеCreate). - Остальные параметры
vc_vdc(провайдер сети, профиль Provider VDC, CPU, RAM, резервирование, storage_config) являются скалярами/числами/JSON-строками и не содержатrefSvcId. - Соответственно, данные запроса
?fields=cfsParamsдляvc_vdcфактически не требуются.
- Шаг 2 в провайдере использовался исключительно для вызова
3. План изменений в провайдере (что будем менять)
Целевой файл: provider/internal/core/client.go
В функции createInstanceWithContext (и при необходимости в runInstanceOperationUniversalByCodeWithTimeout / updateResourceWithTimeout) заменяется жёсткое падение на условный graceful fallback:
opDetailsResp, _, err := c.doRequest(ctx, "GET", fmt.Sprintf("/instanceOperations/%s?fields=cfsParams", opUid), nil)
if err != nil {
// Проверяем, есть ли среди переданных строковых параметров не-UUID значения,
// требующие резолвинга через refSvcId.
// Если все строковые параметры уже UUID или числа/литералы — логируем предупреждение и продолжаем.
c.logWarn(ctx, "не удалось получить cfsParams для операции %s (%v), продолжаем отправку параметров", opUid, err)
} else {
var opDetails universalOpResponse
if err := json.Unmarshal(opDetailsResp, &opDetails); err == nil {
params, err = c.resolveRefSvcParamValues(ctx, opDetails.InstanceOperation.CfsParams, params)
if err != nil {
return "", err
}
}
}
Критерии безопасности:
- Fallback условный: если бэкенд упал, но параметры уже валидны / являются UUID — выполнение продолжается.
- Логируется явный warning с идентификатором операции
opUidи телом ошибки. - Валидация значений параметров не теряется — её по-прежнему выполняет бэкенд на этапе
GET /validate-cfs.