- NOTES/: 10_plans, 20_prompts, 30_analysis, 40_chat_summaries, 60_reference + README в каждой папке - HOW_TO/: все общие инструкции (сборка/заливка, DevOps-ранбук, добавление сервиса, миграция, генерация доков) + индекс «что нужно -> какой файл» - новый README.md: карта проекта, пайплайн, стенды, реестр, запреты/грабли - HOWTO-UPLOAD.md: исправлена легаси-схема версий (prod=1.*, dev=2.*, test=3.*) - DEVOPS_BUILD_PIPELINE.md: пути скриптов -> TOOLS/scripts, universal_rebuild/main.go -> provider/main.go - howitwasdone.md / MIGRATION_PLAN_FOR_AGENT.md: пометки о соответствии старых путей - внутри перенесённых файлов обновлены ссылки на новые пути
20 KiB
20 KiB
Forensic Analysis: API Model to Ordinary YAML
Анализ от Gemini 3.8 flash.
Исследование проведено строго в границах требований FORENSIC_ANALYSIS_BRIEF_2026-09-23.md.
1. Подтверждённые факты
- Цепочка генерации YAML: Инструмент
yaml-generator(TOOLS/yaml-generator/main.go) опрашивает live HTTP REST Gateway API Nubes по сети и сериализует результат в YAML-файлы спецификаций (generated/{stand}/resources_yaml/{service_id}_{name}.yaml), используя структуры контракта TOOLS/lib/types.go. - Спецификации сервисов в репозитории: Канонические сгенерированные спеки сервисов физически размещены в generated/dev/resources_yaml/. В частности, 19_vc_org.yaml и 22_vc_nsxt.yaml.
- В
vc_org.yaml:- Операция
modifyимеет числовой ID207,kind: instance,action: modify. - Параметр
vIPConfigureприсутствует как параметр операцииmodifyс числовым ID662, типомdata_type: array-map-fixed,required: true. - Поле
countприсутствует внутриsub_paramsпараметраvIPConfigureс числовым ID40,data_type: integer > 0,required: true,is_modifiable: false. - Поле
nameприсутствует внутриsub_paramsпараметраvIPConfigureс числовым ID39,data_type: string,required: true,is_modifiable: false.
- Операция
- В
vc_nsxt.yaml:- Операция
modifyимеет числовой ID111,kind: instance,action: modify. - Параметр
ipSpaceNameприсутствует в операцииmodifyс числовым ID372,data_type: string,required: false,sort: 50. - С ним рядом в операции
modifyприсутствуют:needEnableAVI(ID368,data_type: boolean,required: false,value_list: ["false", "true"]);virtualServicesCount(ID369,data_type: integer > 0,required: false,minvalue: 1,maxvalue: 4);qosProfile(ID856,data_type: string,required: false);routedNetConfiguration(ID1112,data_type: map-fixed,required: true, с вложенными подполямиipAddrPool,mainDns,secondDns).
- Операция
- Генератор ресурсов (Ordinary Resource Generator):
- Расположен в TOOLS/resource-generator/main.go.
- При
op.Kind == "instance"(что установлено дляmodifyв generated/dev/resources_yaml/19_vc_org.yaml и generated/dev/resources_yaml/22_vc_nsxt.yaml) генератор объединяет параметрыcreateиmodifyв схему одного общего ресурсаnubes_vc_org/nubes_vc_nsxt. - Параметры, отсутствующие в операции
create, но присутствующие в операцииmodify(какvIPConfigureвvc_org), не включаются в жизненный циклcreate, а при отсутствии отдельной разметкиkind: modifierв YAML генератор не создаёт под них отдельного ресурса модификатора.
2. Исходная API-модель
- Источник и формат: Модель получается HTTP-клиентом (TOOLS/yaml-generator/internal/client/client.go) по протоколу HTTP GET в формате JSON.
- Эндпоинты API:
- Метаданные сервиса и список операций:
GET /services/{svcId}(возвращаетtypes.ServiceResponse). - Метаданные конкретной операции:
GET /instanceOperations/default/{svcOperationId}(возвращаетtypes.ServiceOperationResponse).
- Метаданные сервиса и список операций:
- Идентификаторы операций и параметров:
- Операция идентифицируется стабильным числовым
svcOperationId(int) и строковым именемoperation(например,"modify","create"). - Параметры идентифицируются стабильным числовым
svcOperationCfsParamId(int) и строковым кодомsvcOperationCfsParam(например,"vIPConfigure","ipSpaceName").
- Операция идентифицируется стабильным числовым
- Вложенные объекты и массивы (
dataDescriptor):- В ответе эндпоинта
/instanceOperations/default/{id}сложная структура передаётся в полеdataDescriptor: map[string]CfsSubParam. - Каждое подполе имеет свой числовой
svcOperationCfsSubparamId, строковый ключ (код подполя),dataType,isRequired,isModifiableDefinition,defaultValue,valueList(строка через запятую или массив).
- В ответе эндпоинта
3. Как ordinary generator читает модель
- Входной поток:
yaml-generatorвызываетcli.GetService(svc.ID)и перебирает списокinfo.Operations. - Чтение операций и параметров:
Для каждой операции вызывается
cli.GetServiceOperation(op.SvcOperationID)(TOOLS/yaml-generator/internal/client/client.go). - Преобразования и нормализация:
- Имена сервисов и операций нормализуются в snake_case функцией
normalize.Identifier(TOOLS/yaml-generator/internal/normalize/normalize.go). - Классификация операции: функция
classifyOperationделит операции наinstance(дляcreate,modify,delete,suspend,resume),subresource(если есть символ подчеркивания) илиaction. - Разворачивание
dataDescriptor: генератор обходитmap[string]CfsSubParam, преобразует подполя в срезtypes.ParamSpecи детерминированно сортирует поsubParams[i].ID. - Сортировка верхнеуровневых параметров по
params[i].ID. - Сортировка операций по имени и ID.
- Имена сервисов и операций нормализуются в snake_case функцией
- Что отбрасывается / не сохраняется в YAML:
- Конкретные HTTP method и URL-пути эндпоинтов API платформы (они зашиты в код клиента, в спек YAML не пишутся).
- Вспомогательные поля
CfsParam, не имеющие тегаyaml:в TOOLS/lib/types.go, если они не сериализуются или приходят пустыми:IsModifiable,IsSensitive(указаны сomitempty). ПолеdataDescriptorкак мапа отбрасывается — сохраняется преобразованный срезsub_params.
4. Как формируется API YAML
- Сериализация структуры
types.ServiceSpecв YAML выполняется через библиотекуgopkg.in/yaml.v3(TOOLS/yaml-generator/main.go). - В результирующий файл пишутся:
- Метаданные сервиса (
name,service_id,service_display_name,service_short_name,service_man). - Стандартная секция
lifecycleиoutputs. - Секция
operationsсо списком операций и всеми их параметрами (id,code,data_type,required,default,value_list,descr,man,sort,sub_params).
- Метаданные сервиса (
5. Цепочка данных для vc_org.vIPConfigure.count
- API Model:
- Эндпоинт
/instanceOperations/default/207возвращает параметр сsvcOperationCfsParamId: 662,svcOperationCfsParam: "vIPConfigure",dataType: "array-map-fixed". - Внутри него поле
dataDescriptorсодержит ключ"count":svcOperationCfsSubparamId: 40,dataType: "integer > 0",isRequired: true,defaultValue: "",descr: "Пример: \1`"`.
- Эндпоинт
- Generator Input:
- Читается в структуру
types.CfsParamс мапойDataDescriptor map[string]CfsSubParam(TOOLS/yaml-generator/internal/types/types.go).
- Читается в структуру
- Internal Generator Representation:
- В TOOLS/yaml-generator/internal/client/client.go мапа
dataDescriptorразворачивается вtypes.ParamSpec.SubParams. Полеcountстановится элементом срезаSubParamsсID: 40,Code: "count",DataType: "integer > 0".
- В TOOLS/yaml-generator/internal/client/client.go мапа
- Generator Transformation:
- Сортируется по ID (
sort.Slice(subParams, ...)).
- Сортируется по ID (
- API YAML:
- Записывается в generated/dev/resources_yaml/19_vc_org.yaml:
- id: 662 code: vIPConfigure data_type: array-map-fixed required: true sort: 10 sub_params: - id: 39 code: name data_type: string required: true default: "" is_modifiable: false - id: 40 code: count data_type: integer > 0 required: true default: "" descr: 'Пример: `1`' is_modifiable: false - Потерь в YAML нет:
vIPConfigureиcountполностью и без искажений сохранены в каноническом YAML спецификации.
- Записывается в generated/dev/resources_yaml/19_vc_org.yaml:
6. Цепочка данных для vc_nsxt.ipSpaceName и связанных параметров
- API Model:
- Эндпоинт
/instanceOperations/default/111возвращает операциюmodifyсервиса 22. - Параметр
ipSpaceNameвозвращается с:svcOperationCfsParamId: 372,svcOperationCfsParam: "ipSpaceName",dataType: "string",isRequired: false,descr: "Имя ip Space для внешнего IP",man: "Необходимо указывать, если включён параметр \Выделить VIP для SNAT`"`,sort: 50.
- В HAR-дампах (HAR/edge_.har) на живом инстансе в рантайме возвращается
valueList: ["no-needed", ...].
- Эндпоинт
- Generator Input:
- Читается в структуру
types.CfsParam(TOOLS/yaml-generator/internal/types/types.go).
- Читается в структуру
- Internal Generator Representation:
- Преобразуется в
types.ParamSpecсо значениямиID: 372,Code: "ipSpaceName",DataType: "string".
- Преобразуется в
- Generator Transformation:
- Нормализуются defaults и value_list через
normalizeDefaultиnormalizeValueList.
- Нормализуются defaults и value_list через
- API YAML:
- Записывается в generated/dev/resources_yaml/22_vc_nsxt.yaml:
- id: 372 code: ipSpaceName data_type: string required: false descr: Имя ip Space для внешнего IP man: Необходимо указывать, если включён параметр `Выделить VIP для SNAT` sort: 50 - Рядом в той же операции сохранены:
needEnableAVI(ID 368),virtualServicesCount(ID 369),qosProfile(ID 856),routedNetConfiguration(ID 1112 с sub_params). - Особенность по
value_list: в статическом22_vc_nsxt.yamlполеvalue_listдляipSpaceNameотсутствует (nullв ответе static-дефолтов эндпоинта/instanceOperations/default/111), хотя в рантайме на конкретном инстансеvalueListдинамически содержит["no-needed", ...].
- Записывается в generated/dev/resources_yaml/22_vc_nsxt.yaml:
7. Что сохраняется
- Полная идентичность сущностей:
service_id,svcOperationId(какidоперации),svcOperationCfsParamId(какidпараметра),svcOperationCfsSubparamId(какidвsub_params). - Строковые коды:
operation, коды параметров (code). - Исходные типы платформы:
dataType(string,boolean,integer > 0,array-map-fixed,map-fixed). - Вся структура вложенности (
dataDescriptor→sub_params). - Флаги
required, валидационные regex, min/max, описания (descr,man), порядок (sort).
8. Что преобразуется или нормализуется
- Имена операций и сервисов приводятся к ASCII snake_case через
normalize.Identifier. dataDescriptorиз мапы ключей преобразуется в упорядоченный срезsub_paramsс сортировкой по числовомуid.- Значения
valueListиdefaultприводятся к строковым представлениям (убираются пробелы, пустые значения приводятся кnil).
9. Что теряется
- HTTP-метод и путь обращения к API (в YAML отсутствуют; генератор считает их внешним знанием рантайма).
- Динамические значения списков выбора (
valueList): эндпоинт дефолтов/instanceOperations/default/{id}возвращает пустойvalueListдля полей, зависящих от конкретного тенанта/инстанса (например, доступныеipSpaceNameдля конкретного VDC/Org).
10. Где происходят потери
- Потери HTTP-метаданных (метод, URL) происходят на этапе маршалинга структуры
types.ServiceSpecв YAML (TOOLS/yaml-generator/main.go), так как они изначально отсутствуют в контракте TOOLS/lib/types.go. - Отсутствие runtime
valueListобусловлено вызовом шаблонного эндпоинта/instanceOperations/default/{id}вместо запроса контекста живого инстанса.
11. Какие данные доступны в API YAML
- Полный перечень всех сервисов, операций (
create,modify,delete,suspend,resume, сабресурсов) и их параметров. - Точные типы платформы (
data_type) и иерархия подполей (sub_params). - Идентификаторы
id(CFS param IDs) и символические коды (code). - Метаданные валидации (обязательность, регулярные выражения, ограничения диапазонов).
12. Какие данные доступны только в API-модели
- Динамические списки допустимых значений (
valueList), вычисляемые бэкендом для конкретного состояния конкретного инстанса (например, список реально существующих ipSpaces организации при вызове modify на Edge). - Внутренние служебные поля платформы CFS, отфильтрованные моделью генератора (
contractId,contragentId,nestedRefData,config,statePath,expression).
13. Неизвестные места
- Неизвестно, возвращает ли платформа Nubes какую-либо схему валидации для эндпоинтов отката/деаллокации (например, принимает ли
vc_org.modifyпустой массивvIPConfigure: []для полного снятия или требует только уменьшенияcount: 0), так как в дефолтной модели операции 207 описан только общий форматvIPConfigure.
14. Что необходимо проверить фактическим API
- Поведение
vc_org(операция 207) при передачеvIPConfigure: []противvIPConfigure: [{"name": "...", "count": 0}]при попытке полной деаллокации IP-пространства. - Поведение
vc_nsxt(операция 111) при передачеipSpaceName: "no-needed"на различных окружениях (Dev/Test/Prod).
Мнение Opus: финальное ревью отчёта
Отчёт признан годным и принят как вход для дальнейшего архитектурного этапа.
Достаточно для дальнейшей работы
- Цепочка
API model → yaml-generator → API YAMLпрослежена по коду, а не по догадкам:classifyOperation,params.Merge, разворачиваниеdataDescriptorвsub_params. - Обе обязательные трассировки (
vc_org.vIPConfigure.count,vc_nsxt.ipSpaceName) доведены до YAML с подтверждением «потерь нет». - Зафиксирован ключевой факт: динамический
valueListесть только в рантайме живого инстанса, а в API YAML его нет. Это прямое ограничение для будущего modifier-слоя. - Неизвестное поведение payload деаллокации (
vIPConfigure: []противcount: 0) помечено какunknown, а не закрыто предположением.
Следствия перед архитектурным этапом
- Под ярлыком «Ordinary Resource Generator» в отчёте упоминаются два разных инструмента:
yaml-generatorпишет спеки, аresource-generatorсоздаёт Go-ресурсы. Для проектированияModifierSpecэто две разные точки вмешательства. vIPConfigureиipSpaceNameприсутствуют только вmodifyи отсутствуют вcreate. В текущей схеме они сливаются в общий ресурс и не имеют отдельного жизненного цикла. Это корень задачи модификаторов.- Runtime-
valueListпридётся получать не из дефолтного эндпоинта, а из контекста инстанса. Это вопрос рантайма провайдера, а не генератора.
Итоговая оценка
Ошибок, которые ломали бы выводы отчёта, не выявлено. Отчёт можно использовать как подтверждённую основу для дальнейшего проектирования.