Files
tf_provider/HISTORY/OPUS/3006_0_answers.md
T

29 KiB
Raw Blame History

Ответы на дополнительные вопросы (сессия 2)

Read memory

Created

Готово: 3006_1_questions.md

8 дополнительных вопросов

# Тема Что нового (после его анализа)
1 Расхождение версий Регистр отдаёт 5.0.55, код — 5.0.51. Откуда 53-55?
2 Полный аудит isDeleted Все ли GET /instances фильтруют deleted? Особенно findInstanceUidByDisplayNameRefSvc
3 Gitea 413 Где nginx-конфиг Gitea в репо? Можно ли увеличить лимит через чарты?
4 Suspend-сервисы Полный список кто поддерживает suspend/resume. Есть ли баги (suspend без resume)?
5 Terraform Operator Почему перезапустился 2 дня назад? Хватает ли компонентов? Где GPG/S3 конфиг?
6 Тестовые стенды Какие реально используются? Legacy или Universal? Дубликаты?
7 auth.k8s.ngcloud.ru OIDC-конфиг, обновление токенов, Keycloak HAR
8 Orphan PVC/STS Откуда storage-check-* PVC? PostgreSQL 0/0 28 дней — почему?

Все вопросы — только чтение файлов в репо, никаких правок. Opus может ответить на большинство из них. Вопросы 3 и 8 частично требуют данных из кластера (не из репо) — он это честно отметит.

Внесены изменения.

Список задач обновлен

Read

Исследую все 8 вопросов через чтение файлов репозитория. Запущу параллельный сбор данных.

Searched for regex /instances\?|/instances"|GET.*instances|page=|isDeleted (**/universal_rebuild/internal/core/*.go), 20 results

Searched for regex findInstanceUidByDisplayNameRefSvc|ListRefServiceInstances, 20 results

Searched for files matching **/devops/profiles/**/profile.env, 3 matches

Read

Нашёл ключевое для вопроса 2 — прочитаю функцию findInstanceUidByDisplayNameRefSvc и файлы версий.

Searched for regex VERSION|version|5\.0\. (**/devops/03_build_and_upload_provider.sh), 13 results

Read , lines 900 to 1010

Read

Read

Вопросы 1 и 2 почти закрыты. Соберу данные по остальным: инфраструктура, suspend-аудит, стенды, auth, orphan-ресурсы.

Searched for regex auth\.k8s\.ngcloud\.ru|keycloak|shturval|client_max_body_size|gitea|storage-check, 20 results

Searched for regex getInstanceDisplayNameByUidRefSvc|findInstanceDisplayNameByUidRefSvc (**/universal_rebuild/internal/core/*.go), 6 results

Read

Read

Searched for regex storage-check|terraform-operator|registry-server|operator, 20 results

Searched for files matching **/{operator,registry-server,registry-server-build,k8s}/**, 3 matches

Read , lines 1057 to 1140

Read

Аудит suspend/resume сервисов

Аудит тестовых стендов

Read

Searched for regex kubeconfig|OIDC|oidc|kube-apiserver|kubectl|HOW_TO_SSH|auth\.k8s, 20 results

Searched for files matching **/TEST_STAND/**/*.tf, 11 matches

Searched for files matching **/PROD_STAND/**/*.tf, 10 matches

Searched for files matching **/RABBIT/**/*.tf, 6 matches

Read

Read

Read

Searched for files matching tf_provider · universal_rebuild/resources_yaml/**/*.yaml, no matches

Searched for files matching tf_provider · devops/profiles/prod/generated/resources_yaml/**/*.yaml, no matches

Searched for files matching tf_provider · devops/profiles/test/generated/**/*.yaml, no matches

Searched for files matching tf_provider · universal_rebuild/resources_yaml/embed.go, 1 match

Read

Read

Read

Read

Read

Read

Read , lines 1 to 50

Read , lines 1 to 50

Read

Read

Read , lines 1 to 100

Read

Read

Read , lines 1 to 100

Read

Read

Read

Read

Read

Read

Read

Searched for regex suspend|resume (tf_provider · devops/profiles/prod/generated/resources_yaml/**/*.yaml), 20 results

Read , lines 1 to 50

Read , lines 1 to 60

Read

Read

Read

Searched for regex suspend|resume (tf_provider · devops/profiles/prod/generated/resources_yaml/**/*.yaml), 187 results

Read , lines 1 to 20

Read , lines 459 to 469

Read , lines 1 to 20

Read , lines 238 to 248

Read , lines 1 to 20

Read , lines 1 to 20

Searched for regex - name:|kind:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/91_redis.yaml), 6 results

Searched for regex - name:|kind:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/117_nifi.yaml), 9 results

Searched for regex - name:|kind:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/112_tenant.yaml), 9 results

Searched for regex - name:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/22_vc_nsxt.yaml), 8 results

Searched for regex - name:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/29_vc_vdc_group.yaml), 10 results

Searched for regex - name:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/100_openwhisk.yaml), 4 results

Проверю наличие operator//k8s/, прочитаю отчёт по gitea/registry и README про реестр.

Searched for files matching **/operator/**, no matches

Searched for files matching **/k8s/**, 3 matches

Read , lines 40 to 127

Read

Финальная проверка: наличие registry-server-build/, детали оператора/S3/GPG в кластере, keycloak HAR.

Searched for files matching **/registry-server-build/**, no matches

Searched for files matching **/HAR/*keycloak*, no matches

Searched for regex S3_ENDPOINT|s3.msk-1|terraform-registry|S3_BUCKET|\.s3cfg, 20 results

Read

Все 8 вопросов исследованы. Ниже ответы в формате находка → файлы → вывод → рекомендация.


Вопрос 1: Откуда версии 5.0.53–5.0.55?

Находка. Версия билда берётся не из main.go, а из профиля стенда:

  • 03_build_and_upload_provider.sh: VERSION = $1 → иначе $PROVIDER_VERSION/$RELEASE_VERSION (из profile.env) → иначе grep из main.go (fallback).
  • profile.env: PROVIDER_VERSION="5.0.55".
  • profile.env: PROVIDER_VERSION="2.1.23" (!).
  • main.go хранит 5.0.51 — это лишь последний fallback, который почти никогда не срабатывает.

Вывод. 5.0.53/54/55 — это ручные билды с тестового стенда: оператор вручную bump-ит PROVIDER_VERSION в profiles/test/profile.env и запускает 03_build...sh. main.go при этом не обновляется (README прямо просит обновлять, но на практике это не делается — отсюда рассинхрон). Важно: prod-профиль застрял на 2.1.23, а test ушёл на 5.0.55 — это две независимые линейки версий. Мой прошлый анализ (3006_0.md) цитировал версии из кода (5.0.51/5.0.52), а регистр отдаёт версию из profile.env (5.0.55) — поэтому они не совпадают.

Рекомендация. Сделать profile.env единственным источником версии и автоматически прописывать её в main.go при сборке (или вычислять main.go-версию из env через ldflags -X). Сейчас 3 источника версии (main.go, test, prod) живут врозь.


Вопрос 2: Полный аудит фильтрации isDeleted

Находка. Все функции, делающие GET к /instances:

Функция Файл isDeleted=false в URL Проверка в коде Статус
FindInstanceByDisplayName client.go (search) / (fallback) isInstanceDeleted() OK
ListRefServiceInstances refsvc_resolve.go IsDeleted + только running OK
findInstanceUidByDisplayNameRefSvc client.go if item.IsDeleted {continue} + status=="deleted" OK (исправлен!)
findInstanceDisplayNameByUidRefSvc client.go нет приемлемо
getInstanceDisplayNameByUidRefSvc client.go — (GET по UID) n/a
GetInstanceState/Raw/Details client.go / instance_outputs.go — (GET по UID) /частично n/a

Вывод.

  • findInstanceUidByDisplayNameRefSvc УЖЕ исправлен — он пропускает deleted в коде (строки client.go) и предпочитает running>suspended. Замечание в 24_ai_analysis_pipeline_architecture_2026_06_30.md («НЕ ИСПРАВЛЕН?») устарело — баг класса #23 здесь закрыт. Единственный недочёт — нет isDeleted=false в URL (лишний трафик, но не баг корректности).
  • findInstanceDisplayNameByUidRefSvc (1058) — единственная функция БЕЗ фильтра deleted ни в URL, ни в коде. Но она ищет по точному instanceUid (уникальному) и возвращает displayName — это обратный маппинг для чтения state, не выбор «того/не того» инстанса. Класс багов #23 здесь не применим. Риск минимальный: вернёт имя deleted-инстанса, если в state остался его UID.

Рекомендация. Косметика: добавить &isDeleted=false в URL findInstanceUidByDisplayNameRefSvc (1057) и findInstanceDisplayNameByUidRefSvc (1060) для экономии трафика. Корректность уже обеспечена. Обновить вывод в файле 24 (он сеет ложную тревогу).


Вопрос 3: Gitea 413 (client_max_body_size)

Находка.

  • charts — пустая (list_dir: folder empty).
  • Манифесты в репо есть только для dashboard: ingress.yaml — ingress для terra.k8c.ru/dashboard, аннотаций client_max_body_size/proxy-body-size нет, и это не Gitea.
  • gitea-naeel.giteak8s.services.ngcloud.ru упоминается только как git_path в resources.tf и закомментированно в luceUNDnode.tf. Сам Gitea — это управляемый сервис Nubes (см. svcs.json: «Gitea», «Комплексная услуга по созданию gitea», service_id 99/114), развёрнутый в кластере giteak8s, а не из этого репо.

Вывод. Конфигурация nginx Gitea в этом репозитории отсутствует. client_max_body_size=1MB задаётся на ingress управляемого Gitea в кластере giteak8s.services.ngcloud.ruвнешняя конфигурация, недоступная для правки из этого репо.

Рекомендация. Лимит правится за пределами репо — на ingress Gitea-инстанса: аннотация nginx.ingress.kubernetes.io/proxy-body-size: "0" (или, например, 512m). Это требует доступа к namespace Gitea в кластере giteak8s. Из репо проблему не решить. (Требует данных кластера — отмечаю честно.)


Вопрос 4: Полный список suspend/resume-сервисов

Находка. YAML-спеки в devops/profiles/prod/generated/resources_yaml/ (43 файла, test идентичен), встроены через //go:embed * в embed.go.

26 сервисов с suspend И resume (service_id): 1 dummy, 2 template, 12 s3, 19 vc_org, 20 vc_org_saas, 21 vc_vdc, 23 vc_vm, 26 vapp, 27 vc_vm_v2, 28 vc_vm_v3, 50 nextcloud, 89 flask, 90 postgres, 92 mongodb, 93 rabbitmq, 94 lucee, 95 nodejs, 96 pgadmin, 98 http, 99 gitea, 115 mariadb, 116 kafka, 119 akhq, 120 clickhouse, 149 valo_tenant, 150 k8s_shturval.

17 сервисов без suspend/resume: 13 s3bucket, 22 vc_nsxt, 25 vcexternalip, 29 vc_vdc_group, 32 vmpostgre, 81 superset, 82 harbor, 88 ziti, 91 redis, 97 nodered, 100 openwhisk, 110 dnszone, 111 dnsrecord, 112 tenant, 113 vc_complex, 114 gitea_complex, 117 nifi.

Вывод.

  • Асимметрии нет: suspend и resume всегда идут парой (26/26). Сервисов «suspend без resume» — 0.
  • suspend_on_destroy_default идеально совпадает с правилом hasSuspend → true: 26 suspend-сервисов = true, 17 = false. Расхождений нет.
  • Логика разделения здравая: stateless (DNS, external IP, tenant) — без suspend; stateful (БД, приложения, VM) — с suspend.

Рекомендация. По этому пункту всё чисто. Стоит лишь добавить в генератор validateSpec()-проверку «если есть suspend, обязан быть resume» как защиту на будущее (сейчас инвариант соблюдён случайно — генератор его не enforce-ит).


Вопрос 5: Terraform Operator — состояние и health

Находка — ключевая. Директорий operator/, registry-server-build/, корневого k8s/ НЕТ в этом checkout (file_search: «No files found»), хотя они активно упоминаются в README.md, REPO_CONTENTS.md, build-registry-image.yml (operator/build/Dockerfile.registry) и deploy-dev.sh (k8s/overlays/dev).

Что есть в репо — описание в 00_system_mechanics.md:

  • 3 компонента: Operator (watch CRD → spawn Job), Registry API (Discovery protocol over S3), Builder Job (golang:1.24-alpine: clone→build→upload S3). Это совпадает с тремя deployment'ами, что вы видели.
  • S3: бакет артефактов terraform-providers, схема пути {hostname}/{namespace}/{provider}/{version}/{file}, REGISTRY_HOSTNAME=terra.k8c.ru. Эндпойнт s3.msk-1.ngcloud.ru (upload_provider_s3.py, REPO_CONTENTS.md).
  • GPG в кластере — ФЕЙКОВЫЙ: 00_system_mechanics.md — «GPG Signing: Сейчас фейковое (создаётся пустой .sig)». Реальная подпись private_key.asc используется только в локальном 03_build...sh, а не в operator-Job.
  • Перезапуск оператора — штатная операция: в cheat-sheet прямо есть kubectl rollout restart deploy/terraform-operator -n terra.

Выводы по вопросам:

  1. Перезапуск 2 дня назад — скорее всего ручной rollout restart (документированная команда подхвата изменений manifests/03-build-script.yaml), а не краш. Подтвердить можно только по kubectl describe pod/--previous логам в кластере. (Требует кластера.)
  2. Трёх deployment'ов достаточно для registry+CI (operator+registry-server+builder-job). Отдельного docs-server нет и не нужен: доки — статика в S3 (terraform-registry/docs/...), publish-docs.sh. cloud-dashboard — отдельный UI, не часть registry.
  3. GPG-ключи: в кластере подпись фейковая (tech debt из system_mechanics); реальный ключ только локально в secrets. S3-доступ оператора — через ENV S3_*/REGISTRY_HOSTNAME в Deployment (должны быть в Secret terraform-operator).
  4. S3-конфиг бакета в репо — только переменные и схема путей; манифест Secret/Deployment отсутствует (он в недостающей папке operator//k8s/).

Рекомендация. Критично: внедрить реальную GPG-подпись в operator-Job (смонтировать private_key.asc как K8s Secret) — сейчас артефакты из кластера подписаны пустышкой, Terraform может ругаться authentication signature from unknown issuer. Также — вернуть operator/+k8s/ в этот репо или явно задокументировать, что они в отдельном репозитории (сейчас CI ссылается на отсутствующие пути).


Вопрос 6: Тестовые стенды — что реально используется

Находка. Все .tf используют только Universal (source = "terra.k8c.ru/nubes/nubes"), Legacy (registry.terraform.io/nubes/nubes) не используется нигде.

Стенд Version Endpoint Активные ресурсы
TEST_STAND/LUCEE 2.0.6 test postgres, lucee
TEST_STAND/MARIA_DB 2.0.8 test mariadb, lucee, flask
TEST_STAND/POSTGRES 5.0.52 test postgres + user + database
TEST_STAND/S3_EVENT_POC 2.1.23 s3bucket ×2
PROD_STAND/PG1 2.1.26 prod postgres, lucee, nodejs, s3bucket
PROD_STAND/POSTGRES 2.1.12 prod postgres, lucee, nodejs
PROD_STAND/RABBIT 5.0.19 test ⚠️ rabbitmq
RABBIT/ (корень) 2.1.10 prod rabbitmq, lucee, nodejs, s3bucket

Выводы:

  1. Все стенды активны (с реальными ресурсами); часть компонентов закомментирована (VM в PG1, flask в PROD/POSTGRES, http-worker в RABBIT).
  2. Сильный разброс версий: test — 2.0.6…5.0.52, prod — 2.1.10…2.1.26. Каждый стенд пинит свою версию.
  3. TEST/POSTGRES не дублирует PROD/POSTGRES: разные версии (5.0.52 vs 2.1.12), имена (pg4tf033 vs pg-tst0), TEST модульный (только БД+user+database с var.realm), PROD связный (БД+lucee+nodejs, хардкод realm). Это разные конфигурации, не дубль.
  4. Аномалия: PROD_STAND/RABBIT/main.tf указывает на test-endpoint (deck-api-test.ngcloud.ru), хотя лежит в PROD_STAND — вероятно ошибка/недо-миграция.

Рекомендация. Привести версии стендов к двум канонам (одна test, одна prod), исправить endpoint в RABBIT, удалить мёртвые закомментированные .tf или вынести в examples/.


Вопрос 7: auth.k8s.ngcloud.ru / Keycloak / shturval

Находка. Поиск auth.k8s.ngcloud.ru, shturval, OIDC, kubeconfig по репо: совпадения только в самом файле вопросов 3006_1_questions.md. В коде/конфигах — ничего.

  • HAR keycloak.nubes.ru.har существует локально, но gitignored (HAR/*.har в .gitignore) — и это Keycloak keycloak.nubes.ru (для управляемых сервисов Nubes), а не auth.k8s.ngcloud.ru.
  • Инструкции по доступу — только HOW_TO_SSH.md (SSH, не kubeconfig/OIDC).
  • kubectl-команды в docs (deploy-dev.sh, ops/*.md) предполагают готовый kubeconfig, способ его получения не описан.

Вывод. Конфигурации OIDC кластера, скриптов обновления токена и инструкций по kubeconfig в репо НЕТ. auth.k8s.ngcloud.ru (realm shturval) — внешняя система аутентификации кластера, никак не отражённая в репозитории. HAR относится к другому Keycloak (сервисный, keycloak.nubes.ru).

Рекомендация. Если доступ к кластеру через auth.k8s.ngcloud.ru нужен регулярно — добавить в secrets (gitignored) инструкцию/скрипт kubelogin/OIDC token refresh, по аналогии с HOW_TO_SSH.md. Сейчас это «племенное знание» вне репо. (Детали OIDC-эндпойнта — за пределами репо.)


Вопрос 8: Orphan PVC storage-check-* и PostgreSQL 0/0

Находка. Поиск storage-check по всему репо: совпадения только в файле вопросов. Ни одного .tf, манифеста или упоминания в docs/HISTORY, создающего storage-check-local/storage-check-vcd. Никаких упоминаний проблемных PostgreSQL-тенантов 509145c3/dc5db45d.

Вывод.

  • storage-check-* PVC не создаются Terraform-конфигами из этого репо. Имена (storage-check-local/storage-check-vcd = local/vCD storage classes) характерны для тестов доступности StorageClass — это типичные probe-PVC, которые создаёт облачная платформа/CSI или сам terraform-operator-Job при проверке хранилища, а не пользовательский TF. Подтвердить, что их делает именно operator, по репо нельзя (код оператора отсутствует в checkout, см. Q5).
  • PostgreSQL 0/0 28 дней с висящими PVC/Service — это suspended/недо-удалённые инстансы: StatefulSet масштабирован в 0 (suspend), но PVC и Service остаются (платформа не чистит при suspend). Это согласуется с семантикой suspend_on_destroy (Q4) и багом 20_destroy_detach_semantics: state_only/suspend оставляет ресурсы в облаке.

Рекомендация. Источник storage-check-* и orphan-StatefulSet'ов нужно искать в кластере: kubectl get pvc storage-check-local -o yaml → смотреть ownerReferences/annotations (кто создатель). Если owner — terraform-operator SA или CSI healthcheck, чистить через него. Из репозитория эти ресурсы не управляются. (Требует доступа к кластеру.)


Сводка

# Вопрос Ответ из репо? Главный вывод
1 Версии 53-55 Полностью Из profiles/*/profile.env, ручной bump; main.go — fallback. prod=2.1.23, test=5.0.55
2 Аудит isDeleted Полностью Все критичные функции фильтруют; findInstanceUidByDisplayNameRefSvc уже исправлен (файл 24 врёт)
3 Gitea 413 ⚠️ Частично Конфига nginx Gitea в репо нет — внешняя config кластера giteak8s
4 Suspend-сервисы Полностью 26 suspend+resume, 0 асимметрий, default совпадает идеально
5 Operator health ⚠️ Частично operator/+k8s/ отсутствуют в checkout; GPG в кластере фейковый; рестарт = штатный redeploy
6 Стенды Полностью Везде Universal, Legacy не используется; разброс версий; RABBIT prod→test endpoint
7 auth.k8s Нет в репо Ни OIDC, ни kubeconfig-скриптов; HAR — другой Keycloak (nubes.ru)
8 Orphan PVC Нет в репо storage-check-* не из TF; orphan PG = suspended-остатки; искать в кластере

Требуют данных вне репо (честно): Q3 (ingress Gitea в giteak8s), Q5 (логи рестарта оператора, Secret S3/GPG), Q7 (OIDC-эндпойнт auth.k8s), Q8 (ownerReferences PVC в кластере).

Сохранить эти ответы в HISTORY/OPUS/3006_1.md или оставить в чате?

Создано задач: 6