# Отчет о проблеме: Ошибка 500 при получении cfsParams для vc_vdc и план исправления ## 1. Проблема При создании виртуального дата-центра `nubes_vc_vdc` (сервис 21 `vc_vdc`, операция создания 9) Terraform завершается с ошибкой клиента: ```text не удалось получить детали операции: ошибка 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. Анализ причины 1. **Место падения в провайдере**: `provider/internal/core/client.go` (строка 272 в `createInstanceWithContext`): ```go opDetailsResp, _, err := c.doRequest(ctx, "GET", fmt.Sprintf("/instanceOperations/%s?fields=cfsParams", opUid), nil) if err != nil { return "", fmt.Errorf("не удалось получить детали операции: %w", err) } ``` 2. **Поведение бэкенда 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. 3. **Сравнение с веб-интерфейсом (HAR/vdc.har)**: - В официальном веб-интерфейсе ЛК запрос `GET /instanceOperations/{opUid}?fields=cfsParams` **вообще не выполняется**. - Браузер выполняет строго следующий флоу: 1. `POST /instanceOperations` -> получает `instanceOperationUid` 2. `POST /instanceOperationCfsParams` -> отправляет каждое значение CFS-параметра 3. `GET /instanceOperations/{opUid}/validate-cfs` -> валидация бэкендом 4. `POST /instanceOperations/{opUid}/run` -> запуск операции в оркестраторе 5. Polling `GET /instanceOperations/{opUid}` -> ожидание статуса завершения 4. **Зачем провайдер делает шаг 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` фактически не требуются. ## 3. План изменений в провайдере (что будем менять) ### Целевой файл: `provider/internal/core/client.go` В функции `createInstanceWithContext` (и при необходимости в `runInstanceOperationUniversalByCodeWithTimeout` / `updateResourceWithTimeout`) заменяется жёсткое падение на условный graceful fallback: ```go 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 } } } ``` ### Критерии безопасности: 1. Fallback условный: если бэкенд упал, но параметры уже валидны / являются UUID — выполнение продолжается. 2. Логируется явный warning с идентификатором операции `opUid` и телом ошибки. 3. Валидация значений параметров не теряется — её по-прежнему выполняет бэкенд на этапе `GET /validate-cfs`.