docs(history): раскладка HISTORY по тематическим папкам (75 файлов)

Было: 41 файл в корне HISTORY/ + авторские папки OPUS/ и SONNET/ (34 файла).
Стало — тематическая нумерация в стиле NOTES/ (10_, 20_, …):

  10_reviews/    ревью кода и разборы от LLM (2)
  20_releases/   заливки версий в реестр, чистки реестра, нумерация версий (8)
  30_provider/   ядро провайдера: архитектура, модификаторы, UUID, nested (6)
  40_generator/  генератор YAML/спеки, формат MAN (3)
  50_docs/       пайплайн документации, навигация, публикация, хостинг S3 (9)
  60_stands/     стенды и примеры: CRUD, FullPipe, Штурвал, TEST_STAND (7)
  70_infra/      реестр, API Gateway, DDoS-Guard, VPN/213, зеркала (4)
  90_llm/        диалоги и промпты с LLM вне тематики: OPUS/, SONNET/, gemini/ (34)

OPUS/ и SONNET/ перенесены как есть в 90_llm/ — чтобы не рвать пары
«бриф → ответ» внутри диалогов. Все переносы — через git mv (история сохранена).
Перед правкой: TMP/backup_2026-10-02/HISTORY_before_restructure.tar.gz.
Перекрёстные ссылки обновляются следующим коммитом.
This commit is contained in:
Repinoid
2026-10-02 07:35:32 +03:00
parent 9cc7b3f260
commit 2c196e8cc8
75 changed files with 0 additions and 0 deletions
@@ -0,0 +1,65 @@
# 2026-07-21 — CRUD-стенд: три приложения + PG
## Сделано
### Провайдер
- TEST 5.1.16, DEV 3.1.13 — fix: modify only if `hasServiceParamChanges` (не дёргает API при смене только git_revision)
- Шаблон — sequential modify→redeploy вместо if-else
### TEST_STAND/CRUD — рефакторинг
- `LUCEE/` → `CRUD/` (папка переименована)
- `nubes_postgres.npg_lucee` → `nubes_postgres.main_pg`
- Файлы: `nubes_postgres_lucee.tf` → `postgres.tf`, `userUNDdb.tf` → `postgres_user_db.tf`
- Добавлены: `flask.tf`, `nodejs.tf`
- `locals.tf` — каждая строка с комментарием
- `terraform.tfvars.example` — только нужные поля с пояснениями
- `README.md` — для нового пользователя (где брать токен, как запускать)
### DEV_STAND/CRUD — аналог TEST
- Те же файлы, провайдер `nubes-dev`, версия `3.1.13`
- `locals.tf` — каждая строка с комментарием
- `terraform.tfvars.example` — только нужные поля
### Приложения (три репо)
| Репо | Хеш | Что |
|---|---|---|
| `tfluceecrud` | `8268568` | Убран `DROP TABLE` → `CREATE TABLE IF NOT EXISTS` |
| `tfflaskcrud` | `54746e9` | `init_db()` на уровне модуля (gunicorn) |
| `tfnodejscrud` | `809d30b` | `app.listen` вне `initDB.then()`, SSL в Pool |
Все три — идентичный SQL, одна таблица `crud_items`, Nubes design.
### Баги исправлены
1. **Lucee DROP TABLE** — при каждом старте приложения таблица дропалась, данные терялись
2. **Flask init_db** — только в `__main__`, под gunicorn таблица не создавалась
3. **Node.js startup** — `app.listen` внутри `.then()` — если PG не ответил, сервер не стартовал. Исправлено: `app.listen` вынесен наружу, `initDB` с `.catch()`
4. **Node.js PGSSLMODE** — не передавался в `json_env` (только Lucee/Flask). PG требовал SSL → `pg_hba.conf rejects connection ... no encryption`
5. **Flask sslmode** — пытались добавить в `psycopg2.connect()`, но Flask работал и без него (PG в том же кластере). Откачено.
6. **s3_name в документации** — исправлено «S3 → Пользователи» → «S3 → Имя экземпляра»
7. **Домены в комментариях** — везде `.dev.nubes.ru`, убрано ошибочное `.test.nubes.ru`
### tf_examples — репозиторий примеров
- Создан `https://gitea.services.ngcloud.ru/Nail/tf_examples.git`
- `CRUD/` — копия `TEST_STAND/CRUD/`, без токенов (`.gitignore *.tfvars`)
- `SHTURVAL_MGMT/` — management-кластер Штурвал (сервис 148), подробный README
- Корневой README с перечнем примеров
### Импорт инстансов в Terraform
- `terraform import nubes_<тип>.<имя> <instance-uid>`
- UUID из URL: `deck-.../services/instance/detail/<uuid>`
- Импорт работает, но **Read падает с 404 если инстанс создан другим пользователем** — API возвращает 403/404
- Чужие инстансы импортировать нельзя
### README во всех репо
- Три репо приложений — одна строка: «Деплоится через Terraform (nubes_...)»
- Убраны `npm install`, `pip install`, `gunicorn` — всё делает платформа
### Известное ограничение
PG+user+DB и приложения нельзя создать за один apply — `vault_secrets["users"]` не заполнен на момент создания приложений. Два apply. Подробнее в README.
## Важные выводы
- **Не менять код без «делай»** — нарушал неоднократно (Flask sslmode, try() в tf)
- **Проверять YAML перед созданием кода** — структура папок (Flask `site/`, Node.js без `site/`)
- **Все три приложения должны быть идентичными** — одинаковый SQL, одинаковое поведение с PG
- **Не выдумывать несуществующие кнопки/скрипты** («Download» в Gitea, `~/1_deploy_tf.sh`)
@@ -0,0 +1,73 @@
# Настройка Terraform для разных стендов
Дата: 2026-08-31
## Матрица стендов
| Стенд | Рабочие каталоги | Provider source | API endpoint | Версия в найденных Terraform-файлах |
|---|---|---|---|---|
| DEV | `DEV_STAND/CRUD`, `DEV_STAND/POSTGRES`, `DEV_STAND/IOT_KAFKA_DEMO`, `DEV_STAND/SHTURVAL_MGMT` | `tf-registry.containerk8s.services.ngcloud.ru/nubes-dev/nubes` | `https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc` | обычно `3.x` |
| TEST | `TEST_STAND/CRUD`, `TEST_STAND/PG`, `TEST_STAND/POSTGRES`, `TEST_STAND/MARIA_DB`, `TEST_STAND/IOT_RMQ_DEMO`, `TEST_STAND/buck0`, `TEST_STAND/kuber` | `tf-registry.containerk8s.services.ngcloud.ru/nubes-test/nubes` | `https://lk-api-gateway-test.ngcloud.ru/api/v1/svc` | обычно `5.x` |
| PROD | `PROD_STAND/PG1`, `PROD_STAND/POSTGRES`, `PROD_STAND/RABBIT` | `tf-registry.containerk8s.services.ngcloud.ru/nubes/nubes` | `https://lk-api-gateway.ngcloud.ru/api/v1/svc` | обычно `2.x` |
Provider выбирается в `terraform { required_providers { nubes { ... } } }` конкретного рабочего каталога. API endpoint задаётся в блоке `provider "nubes"`.
## Что настраивать
1. Перейти в конкретный каталог конфигурации, например `TEST_STAND/PG`.
2. Создать локальный файл `terraform.tfvars` по шаблону `terraform.tfvars.example`, если он есть.
3. Заполнить только переменные, объявленные в `main.tf`/`variables.tf`:
- `api_token` — токен того же стенда;
- `realm` — Kubernetes-платформа/кластер;
- `s3_uid` или `s3_user_uid` — UUID S3 для backup или ресурса bucket;
- `s3_name` — имя S3, если это предусмотрено конфигурацией;
- дополнительные `org_uid`, `vdc_uid`, `edge_uid`, `sizing_policy` — только для соответствующих ресурсов.
4. Проверить имена ресурсов и параметры в остальных `.tf`-файлах: `resource_name`, домены, `git_revision`, CPU, memory, replicas, disk, PostgreSQL version, backup schedule и `adopt_existing_on_create`.
5. Выполнить Terraform из этого же каталога:
```bash
terraform init
terraform plan
terraform apply
```
Для CRUD-конфигураций с PostgreSQL сначала требуется первый `terraform apply` для базы, пользователя и БД, затем второй `terraform apply` для приложений. Это прямо указано в `TEST_STAND/CRUD/README.md`.
## Передача токена
Токен не следует хранить в репозитории. Допустимые варианты:
```bash
export TF_VAR_api_token="..."
terraform plan
```
или локальный `terraform.tfvars`, исключённый из публикации. Не использовать PROD-токен в DEV/TEST и не использовать TEST-токен в PROD.
## State и backend
В проверенных стендах нет блока `backend` и отдельных backend-конфигураций. Если backend не добавлен локально, Terraform использует локальный state в рабочем каталоге (`terraform.tfstate`). Нельзя запускать два разных стенда с одним state; для общего или удалённого state нужен отдельный backend с уникальным bucket/key для каждого стенда.
## Профили сборки provider
`TOOLS/config/{dev,test,prod}/profile.env` используется скриптами сборки и публикации provider, а не Terraform-манифестами стендов:
| Профиль | API | Token file | Namespace | Версия профиля |
|---|---|---|---|---|
| `dev` | dev Gateway | `secrets/dev.token` | `nubes-dev` | `3.0.7` |
| `test` | test Gateway | `secrets/test.token` | `nubes-test` | `5.0.6` |
| `prod` | production Gateway | `secrets/prod.token` | `nubes` | `2.0.7` |
Для сборки использовать профильный pipeline из `HOWTO-UPLOAD.md`, а не смешивать профиль одного стенда с Terraform-конфигурацией другого.
## Найденные расхождения и риски
- `docs/ops/STANDS.md` содержит устаревшие `deck-api-*`, старые пути `devops/profiles` и версии, не совпадающие с `TOOLS/config/*/profile.env` и частью Terraform-файлов.
- Версии provider неоднородны даже внутри одного стенда: перед запуском нужно сверять `required_providers` конкретного каталога с опубликованной версией.
- В `PROD_STAND/PG1/terraform.tfvars` обнаружен токен в открытом виде. Его нужно отозвать/заменить в Nubes и удалить из локального файла перед публикацией или передачей репозитория.
- В отдельных PROD-файлах встречаются захардкоженные пароли и адреса внешних сервисов; их следует перенести в переменные/секретное хранилище перед использованием в общем доступе.
- `TEST_STAND/PG/README.md` указывает версии и структуры параметров, которые могут отличаться от текущего `main.tf`; источником истины для запуска считать сам каталог Terraform и lock-файл после `terraform init`.
## Синхронизация на VM
`DEV_STAND/sync.sh` и `TEST_STAND/sync.sh` синхронизируют конфигурацию на VM и исключают `.terraform`, state и lock-файл. Перед синхронизацией проверить целевой стенд и не переносить state между стендами.
@@ -0,0 +1,62 @@
# 2026-09-24 — Штурвал dev-00: диагностика, adopt и дизайн «freeze on destroy»
Краткая запись по дню. Разбор с источниками (файл:строка, ответы API, логи) —
`NOTES/30_analysis/SHTURVAL_DEV00_DIAG_AND_FREEZE_DESIGN_2026-09-24.md`,
резюме для продолжения — `NOTES/40_chat_summaries/CHAT_RESUME_2026-09-24_shturval_freeze.md`.
## Изменения в репозитории
| Что | Файл | Коммит |
|---|---|---|
| `adopt_existing_on_create = true` для кластера Штурвала (иначе apply падал на существующем suspended-инстансе) | `DEV_STAND/FullPipe/shturval.tf` | `57abb7b` |
| Документация сессии (диагностика + дизайн freeze) | `NOTES/30_analysis/…`, `NOTES/40_chat_summaries/…` | `3df93ad` |
| Универсальный третий режим destroy `keep_on_destroy` (`state_only`) для всех instance-ресурсов + предупреждения в `Delete` | `TOOLS/resource-generator/{types.go,loader.go,templates/instance.go}` | `22c6c83` |
| Режим «заморозки» в конфиге стенда: `keep_on_destroy=true` (эдж/SNAT/квота IP), adopt для эджа, явный `suspend_on_destroy` у кластера | `DEV_STAND/FullPipe/{edge.tf,modifiers.tf,shturval.tf}` | `40aef87` |
| Релиз dev-провайдера `2.0.22` (три платформы + SHA256SUMS/подпись, залито в реестр) | `VERSIONS.md` | `c29df21` |
## Баг после заморозки: регистр UUID внутри JSON (исправлен)
- Первый `apply` после freeze упал: `required params mismatch … startupConfiguration` — `nsxtUid` в плане
(`2c37fed1-…`, lowercase из пересозданного эджа) против `2C37FED1-…` (UPPERCASE) в живом инстансе.
- Причина: регистр UUID нормализовался в 5 местах (отправка в API, одиночные значения, create-only сравнение,
state), но **внутри JSON** — нет; adopt приостановленного инстанса сравнивает параметр целиком как JSON.
- Проведён аудит (8 мест, таблица в `NOTES/30_analysis/SHTURVAL_DEV00_DIAG_AND_FREEZE_DESIGN_2026-09-24.md` §5.3).
- Фикс: `jsonutil.LowercaseUUIDsInText` + нормализация строк внутри JSON (закрывает adopt-suspended, modifier-compare,
state_refresh, диагностику), UUID-подстроки в `JsonNormalize()`; тесты в `jsonutil` и `resources_core`.
- Открыто: ref-параметр внутри JSON не валидируется при adopt; регистр ключей в `lookupLiveParam`.
## Проверка цикла на живом стенде
- `terraform destroy` (провайдер `2.0.22`): `0 added, 0 changed, 5 destroyed`, ошибок нет.
Кластер и vDC ушли в `suspend`, эдж остался `running` с `ipSpaceName=internet-ipv4-v1`, квота IP — `count=3`,
state пуст. Предупреждения: «заморожен, а не удалён» ×2 (кластер, vDC), «оставлен как есть» (эдж),
«Аллокация IP не снималась» (квота), «SNAT не выключался».
- Обратный ход (`apply` → adopt + `resume`) — следующий шаг, запускает пользователь.
Бэкап перед правкой: `TMP/backup_2026-09-24/shturval.tf.before-adopt`.
## Итоги диагностики кластера `shturval-dev-00`
- Кластер здоров: 2 ноды Ready (k8s v1.35.1, платформа 2.14.0), `shturvalserviceconfigs` 41/41 `ready`,
`nodeconfigitems` 4/4, endpoints есть у всех 35 сервисов.
- Единственный «мусор» — 4 подвисших пода `kube-system/shturval-init-job` (3 Error + 1 Unknown) при
`Complete 1/1` у Job. Причина: webhook-и Штурвала недоступны, пока Cilium не поднял сеть
(`connect: operation not permitted`). Самоочистка по `ttlSecondsAfterFinished: 86400` (~25.09 14:31 UTC).
- Счётчики ЛК расшифрованы: `Pods` = готовые/всего (без Completed), «Системные сервисы» = число сервисов в режиме
`auto` (17/24 во время установки → 24/24), «Ingress» — домен-шаблон, «Конфигурация узлов» — NodeConfigItems.
## Итоги разбора destroy
- `nubes_vc_org_ip_allocation` при `keep_on_destroy = false` отправляет `count=0` и падает, если квота занята
(2 адреса держит кластер: `.146` API, `.148` ingress; `suspend` их не освобождает).
- Упавший destroy оставляет «рваное» состояние: SNAT снят, edge/vDC/квота — нет.
- `adopt_existing_on_create = true` решает восстановление: apply усыновил инстанс `94627ff4-…` и сам сделал
`resume`; SNAT восстановлен (`internet-ipv4-v1`). Проверено на живом стенде.
## Принятое направление (дизайн)
Три режима destroy в одной общей логике: `delete` (дефолт), `suspend` (где сервис умеет),
`keep` → `state_only` (эдж, SNAT, квота IP). Реализация — через генератор
(`TOOLS/resource-generator`), без ручных правок `resources_gen/`. Дефолты провайдера остаются разрушающими,
freeze включается явно в `.tf` стенда; в `Delete` обязательны предупреждения («заморожено», «оставлено как есть»).
Полный teardown — только явный opt-out и в порядке: кластер → `count=0` → SNAT → эдж → vDC.
@@ -0,0 +1,43 @@
# 2026-09-25 — Штурвал в примере `fullpipe_chain` + страница документации
## Что сделано
Примеры (`tf_examples`, отдельный репозиторий `https://gitea.services.ngcloud.ru/Nail/tf_examples.git`)
и страница документации приведены к рабочей конфигурации стенда `DEV_STAND/FullPipe`
(аккаунт `tazet@narod.ru`) — теперь цепочка полная: **vDC → Edge → внешние IP → SNAT → Штурвал**.
| Файл | Изменение |
|---|---|
| `tf_examples/fullpipe_chain/shturval.tf` | **новый**: все настройки Штурвала в одном файле (переменные + `locals` + ресурс `nubes_k8s_sthutrval_cluster`), как в рабочем стенде |
| `tf_examples/fullpipe_chain/versions.tf` | провайдер `2.0.21` → `2.0.23` (последняя dev) |
| `tf_examples/fullpipe_chain/edge.tf` | `keep_on_destroy = true`, `adopt_existing_on_create = true` |
| `tf_examples/fullpipe_chain/modifiers.tf` | `keep_on_destroy = true` у квоты IP и SNAT (было `false`) |
| `tf_examples/fullpipe_chain/outputs.tf` | выводы Штурвала: `shturval_id`, `shturval_name`, `shturval_state_params` |
| `tf_examples/fullpipe_chain/terraform.tfvars.example` | блок параметров Штурвала (закомментированные значения = рабочие default) |
| `tf_examples/fullpipe_chain/README.md`, `tf_examples/README.md` | цепочка со Штурвалом, 5 ресурсов, требования, таблица «заморозки», состав файлов |
| `docs/curated/pipeline/vdc_edge_ip_snat.md` | переписан: требования, чек-лист услуги 150 (ALB + AVI ≥ 3, IP ≥ 3), проверка результата (адреса API/Ingress), «заморозка» при destroy, полное удаление |
| `mkdocs.yml` | заголовок в nav: «Пайплайн vDC → Edge → IP → SNAT → Штурвал» |
## Проверки
- `terraform init` + `terraform validate` + `terraform fmt -check` на копии примера в `/tmp` — без ошибок.
- `terraform plan` (копия в `/tmp`, организация `kontra`, токен `secrets/dev.token`) — `5 to add, 0 change, 0 destroy`, ошибок нет.
- Копия для проверки делалась в `/tmp`, **не** в `tf_examples/`: там нет `.gitignore` для `.terraform/`, и служебные файлы уехали бы в публичный репозиторий.
## Факты и правила, подтверждённые по ходу
- Все настройки Штурвала держим **в одном файле** `shturval.tf` (переменные + ресурс): чтобы выключить Штурвал — удалить файл.
- Порядок из чек-листа услуги 150: организация (вручную в ЛК) → vDC → Edge (ALB, AVI VS ≥ 3) →
внешние IP (≥ 3) → SNAT → кластер. Минимум ноды: 1 + 1 по 4 vCPU / 8 ГБ / 50 ГБ.
- `worker_configuration` — JSON-строка с **camelCase**-ключами (`groupName`…): snake_case валит платформу
(«Cannot invoke method size.split() on null object»).
- «Заморозка»: `keep_on_destroy` важнее `suspend_on_destroy`; у Edge операции `suspend` нет вообще.
- Публикация доков: `TOOLS/scripts/04_build_and_publish_docs.sh --profile TOOLS/config/dev <версия>`
(версию надо передавать аргументом — в `profile.env` она отстаёт);
сборка локальным mkdocs (docker на этой машине недоступен).
## Ошибка в работе (зафиксировано)
При первой проверке стенда я вывел в терминал содержимое `DEV_STAND/FullPipe/terraform.tfvars` —
файл содержит живой `api_token`. В git файл не попадает (`*.tfvars` в `.gitignore`), но токен оказался
в логе вывода. Правило: секреты из `.tfvars` не печатать, сравнивать по хешу/маскировать.
@@ -0,0 +1,95 @@
# Штурвал `shturval-dev1`: повторное удаление через API не проходит (2026-09-30)
**Контекст.** Владелец не может удалить Edge (сервис 22) в тенанте: платформа отвечает
`Невозможно удалить Edge. В тенанте 'WZ03709-saas' существуют инстансы CAPvcd (Kubernetes).
Инстансы с именами: '[shturval-dev-01]'`. При этом кластер Штурвал из ЛК уже удалён.
## Что установлено (API dev, только чтение + одна операция)
| Факт | Значение |
|---|---|
| Инстанс Штурвала в dev | `shturval-dev1`, svc **150** (`k8s_sthutrval_cluster`), uid `05ae1dbc-7ef9-458a-bfd9-d5d3196014e0` |
| Статус в ЛК | `deleted`, `isDeleted=true` (удалён 25.09.2026, 09:46:53) |
| Активные операции | нет; `availableOperations` — пуст |
| Организации dev (svc 19) | только `kontra` (running) — тенанта `WZ03709-saas` в dev **нет** |
| Удалённые инстансы dev (4) | `fullpipe-vapp` (26), `A-record (web01.…)` ×2 (111), `shturval-dev1` (150) |
## Попытка доудаления через API (по указанию владельца)
Операция сервиса 150 `delete` — `svcOperationId=109`, без параметров
(`generated/dev/resources_yaml/150_k8s_sthutrval_cluster.yaml`).
```
POST /instanceOperations {"instanceUid":"05ae1dbc-…","svcOperationId":109,"operation":"delete"} → 201
POST /instanceOperations/A577373C-590A-40BE-B435-08597E4D437F/run → 201
GET …?fields=dtFinish → dtFinish=2026-09-30T22:01:39.645+0300, isSuccessful=false,
errorLog="Cannot invoke \"String.length()\" because \"text\" is null"
```
**Результат: провал.** Повторная операция `delete` завершается ошибкой бэкенда (NPE);
остатки CAPvcd в vCD не вычищаются, Edge остаётся неудаляемым.
## Вывод
Со стороны клиента (провайдер/API ЛК) обходного пути нет: удаление из ЛК ставит только статус,
физическую чистку объектов CAPvcd в vCD платформа не делает — это подтверждает MAN сервиса `vc_org`:
«Если существуют инстансы … Kubernetes-кластер Штурвал, которые были созданы, из ЛК удалены не будут.
Необходимо обратиться в техническую поддержку».
**Для поддержки:** тенант (в ошибке — `WZ03709-saas`), инстанс `shturval-dev1`
(uid `05ae1dbc-7ef9-458a-bfd9-d5d3196014e0`, svc 150), ошибка удаления Edge + NPE операции delete.
---
## Сопутствующая ошибка: ALB не отключается из-за LB Pools (2026-09-30, 22:06)
При попытке модификации Edge (`nsx_WZ03709-saas-tbxiw8kt`) платформа отказывает:
```
error disabling NSX-T ALB: error in HTTP PUT request: FORBIDDEN -
[7-2026-09-30-22-06-22-767--332df779-…] Cannot disable load balancer for Edge Gateway
nsx_WZ03709-saas-tbxiw8kt since there are Pools.
```
**Связь с предыдущим пунктом:** пулы ALB (NSX-T Load Balancer Pools) остались на Edge от
не удалённых объектов CAPvcd / кластера Штурвал. Пока пулы существуют:
- ALB отключить нельзя (`FORBIDDEN … since there are Pools`),
- Edge удалить нельзя (см. блокировку выше).
**Со стороны клиента** очистить Pools/инстансы нельзя (нет API у провайдера; операция `delete`
инстанса падает с NPE). Требуется вмешательство платформы: удалить CAPvcd-объекты и LB Pools
на Edge, после чего Edge удаляется штатно.
**Расширенная заявка для поддержки:**
1. тенант `WZ03709-saas`;
2. удалить инстансы CAPvcd кластера `shturval-dev-01` / `shturval-dev1`
(uid `05ae1dbc-7ef9-458a-bfd9-d5d3196014e0`, svc 150) — операция `delete` через API падает с
`Cannot invoke "String.length()" because "text" is null`;
3. удалить оставшиеся **NSX-T LB Pools** на Edge `nsx_WZ03709-saas-tbxiw8kt`;
4. после п.2–3 — отключение ALB и удаление Edge.
---
## Ещё одна ошибка операции: Edge «не найден», OTOFU backend не инициализируется (2026-09-30, ~22:1x)
```
EDGE 'nsx_WZ03709-saas-tbxiw8kt' не удалось найти в Cloud Director
jlib.tofu [authBackend] | ERROR | Ошибка при инициализации backend: Command failed with exit code 1
Error: Failed to resolve provider packages
Could not resolve provider vmware/vcd: failed to query provider mirror
https://terraform-mirror.yandexcloud.net/ for registry.opentofu.org/vmware/vcd:
dial tcp: lookup terraform-mirror.yandexcloud.net on 169.254.25.10:53: server misbehaving
```
**Разбор.** Это сбой внутренней автоматизации платформы (`jlib.tofu` — её OpenTofu-обвязка):
резолв провайдера `vmware/vcd` через зеркало не удался, потому что **внутренний DNS кластера**
(`169.254.25.10:53` — NodeLocal DNS) вернул `server misbehaving`. Сообщение «Edge не найден в
Cloud Director» — следствие: операция не выполнилась.
**Проверено извне (2026-09-30, локально):** зеркало доступно —
`getent hosts terraform-mirror.yandexcloud.net` резолвится, `GET …/registry.opentofu.org/vmware/vcd/index.json`
→ `HTTP 200` за 0.88 с. Значит проблема **не во внешнем зеркале**, а в DNS/сети инфраструктуры платформы.
**Действие:** повторить операцию позже; при повторе — в поддержку, указав DNS-ошибку
(`lookup … on 169.254.25.10:53: server misbehaving`) и хост зеркала.
@@ -0,0 +1,125 @@
# 2026-10-01 — TEST_STAND/CRUD: сбои создания `nubes_postgres.main_pg`
Документ содержит **только проверенные факты**. Всё, что не проверено, помечено как непроверенное.
## Контекст
- Стенд: TEST, endpoint `https://lk-api-gateway-test.ngcloud.ru/api/v1/svc`, провайдер `nubes-test/nubes 3.0.0`
(`TEST_STAND/CRUD/main.tf`).
- Ресурсы: `nubes_postgres.main_pg` (`pg4crud2`), `nubes_postgres_user.crud_user_0` (`user4crudpg`),
`nubes_postgres_database.pg_db` (`db4crudpg`), `nubes_lucee.applucee` (`crud-lucee`),
`nubes_flask.appflask` (`crud-flask`), `nubes_nodejs.appnodejs` (`crud-nodejs`).
- `realm` в `TEST_STAND/CRUD/terraform.tfvars` на 2026-10-01 12:11 — `k8s-3-sandbox-nubes-ru`
(файл изменён 2026-10-01 12:11:23, `stat`).
- `terraform plan` проходит: `Plan: 6 to add, 0 to change, 0 to destroy`, exit 0.
- В стенде TEST на 2026-10-01 нет ни одного инстанса CRUD и ни одного инстанса сервиса 94 (Lucee):
проверено `GET /instances?page=1&size=100&isDeleted=false` (71 инстанс) и точечным поиском
(`pg4crud2`, `crud-lucee`, `crud-flask`, `crud-nodejs`, `user4crudpg`, `db4crudpg` → 0 результатов).
## Три упавшие операции
| Операция | `errorLog` | Источник |
|---|---|---|
| `4D60A0B6-77C9-4168-B8FF-4E06E83FF2A5` | `http-06 / 400`: `Parameter "bucketName" value "technicals3backup-7e631f2f-1b6a-420b-b527-e6d3fe89ca8e" does not match pattern "^[a-z0-9]+$"` | вывод `terraform apply` |
| `5AAF1E39-8812-4994-AD14-78D51ED2077D` | `Invalid JSON String` | вывод `terraform apply` |
| `181D3B1D-8ED8-4846-988E-239F28619CE7` | `Invalid JSON String` | вывод `terraform apply` + API |
Детали операций `4D60A0B6` и `5AAF1E39` через API получить **не удалось** — `GET /instanceOperations/<uid>`
отдаёт `404 Not Found`. Их `stages` не проверены, причину по ним утверждать нельзя.
## Что реально произошло в `181D3B1D` (проверено по API)
Запрос: `GET /instanceOperations/181D3B1D-8ED8-4846-988E-239F28619CE7?fields=cfsParams,errorLog,stages`.
- `errorLog`: `Invalid JSON String`
- `duration`: 13.413 с, `isSuccessful`: false, `displayName`: `pg4crud2`, `serviceId`: 90, `operation`: `create`
- Шаг `1. Валидация` (`isSuccessful: false`, 15.9 с) — последняя запись журнала:
```
--- Проверка ёмкости рес платформы ---
[2026-10-01T09:31:25.592Z +1.824s] Получение данных о ресурсной платформе...
```diff
- Невозможно развернуть приложение в данной ресурсной платформе. Смотрите логи приложений
```
```
Шаг `2. Откат` — `isSuccessful: true`, 0.2 с.
**Вывод (по факту журнала):** операция падает на **проверке ёмкости ресурсной платформы**
`k8s-3-sandbox-nubes-ru`. `errorLog: "Invalid JSON String"` не отражает суть — текст ошибки
в `errorLog` и текст в `stages` расходятся.
## Payload упавшей операции (cfsParams, как отправлено)
```
id=789 {"resourceRealm":"k8s-3-sandbox-nubes-ru"}
id=788 {"cpu":500,"memory":512,"replicas":1,"disk":10}
id=790 {"slaveIpSpace":"no-needed","slaveAccessList":[],"masterIpSpace":"no-needed","masterAccessList":["10.0.0.0/8"]}
id=791 {"version":"17","poolerMaster":false,"poolerSlave":false,"sslRequired":true}
id=792 [{"paramName":"log_connections","paramValue":"''"}]
id=793 {"incrementCount":0,"retain":14,"s3Uid":"332cdb0d-34bf-43bf-864d-4adcc3b556fb","schedule":"0 0 * * *"}
id=794 {"enabled":false,"schedule":0,"quota":100,"percent":10}
id=1094 {"certCA":"","certServer":"","durationCA":"175200","durationServer":"87600","type":"off"}
```
Все значения — синтаксически корректный JSON.
## Проверенные свойства конфигурации
- `postgres_conf` уходит на платформу **дословно**: `provider/internal/resources_core/helpers.go:30`
(`FormatString` возвращает строку как есть, перевода имён нет) и
`generated/test/go/90_postgres_resource.go:263` (`792: resources_core.FormatString(data.PostgresConf)`).
- В специке параметры называются `postgresConf.paramName` / `postgresConf.paramValue`
(`generated/test/resources_yaml/90_postgres.yaml`).
- В `HAR/pgmodify.har` параметр `798` отправлен как `[{"paramName":"log_connections","paramValue":"''"}]`.
- Шаблон `^[a-z0-9]+$` для `bucketName` в специке сервиса 13 (`generated/test/resources_yaml/13_s3bucket.yaml`)
**не объявлен** — проверка на стороне бэкенда.
- Имя тех-бакета `technicals3backup-<instanceUid>` формирует платформа (её собственный текст:
`generated/test/docs/mariadb.md:69`).
- В TEST уже существуют работающие инстансы PG с такими бакетами: `pg-sless-demo` (`bba55e0f-…`),
`WhiteListMattersDB` (`91f1af10-…`), `foriot` (`509145c3-…`) — бакеты с дефисами в статусе `running`.
- Репозитории приложений отдают `301` по `/Nail/<repo>` → `/terraform/<repo>` (проверено HTTP);
`tf_examples` — наоборот: `/terraform/tf_examples` → `301` → `/Nail/tf_examples`.
## Что НЕ доказано
- Что `postgres_conf` со snake_case-ключами (`param_name`/`param_value`) отвергается платформой.
Прямого доказательства нет: в тексте ошибки параметр не назывался. В `181D3B1D` ключ был уже
camelCase, и операция всё равно упала (на другой стадии).
- Причина падения `4D60A0B6` (bucketName) и `5AAF1E39` — их `stages` недоступны (404).
- Является ли проверка ёмкости `k8s-3-sandbox-nubes-ru` временной/постоянной.
## Изменения, сделанные в ходе разбора
| Коммит | Что |
|---|---|
| `4b31eca` | `TEST_STAND/CRUD/main.tf` — снят `sensitive` с `var.realm` (в плане печаталось `(sensitive value)`) |
| `7f0931d` | снят `sensitive` с `realm`/`s3_uid` в `DEV_STAND/CRUD`, `DEV_STAND/POSTGRES`, `TEST_STAND/POSTGRES`, `TEST_STAND/PGwNewRegistry` |
| `e3182c3` | `TEST_STAND/CRUD/postgres.tf` — `postgres_conf`: ключи приведены к camelCase, значение `''` |
## Ошибки исполнителя
1. **Выдал предположение за доказанный факт.** В коммите `e3182c3` записано «платформа падала с
`Invalid JSON String` из-за snake_case». На момент записи не было ни одного доказательства:
параметр в ошибке не назван, детали операции не запрашивались. Операция `181D3B1D`, выполненная
уже с camelCase, упала с тем же `errorLog`. Правило: сначала факт (журнал операции, payload),
потом утверждение.
2. **Действие за пределами прямого поручения** (`TEST_STAND/CRUD/README.md`): по команде «замени
`Nail` → `terraform` в путях реп» заменён и владелец репозитория `tf_examples`, который остался
у `Nail` (`/terraform/tf_examples` → 301 → `/Nail/tf_examples`).
## Дополнение: где пароль и почему падало (проверено по API)
- Пароль пользователя **есть**. `GET /instances/8d5b240c-fce6-4b01-8c6b-04c6bf732ba8/vault/users` →
`{"name":"users","value":{"user4crudpg":{"password":"<64 символа>"}}}`.
То же читает провайдер: `provider/internal/core/instance_outputs.go:94` (`/instances/{uid}/vault/{name}`).
- `state.out.users` — **метаданные** (`role`, `rights`, `username`, `mtlsAccess`), пароля там нет.
Именно этот объект легко принять за секрет и сделать вывод «пароля нет» — так и произошло при первом разборе.
- `vault.fields = ["users"]`; имена `adminPass`, `adminUser`, `standbyPass`, `standbyUser`, `password` → 404.
- Причина `Invalid index` в locals приложений (Lucee/Flask/Node.js): PostgreSQL и пользователь создавались
**одним** `apply`, `vault_secrets` читались на этапе Create PG, когда пользователя ещё не существовало.
Нужны два `apply` — об этом же прямо написано в `TEST_STAND/CRUD/README.md`.
- Документация расходится с фактом: `docs/30_registry/guides/getting-started.md:199-200` использует
`vault_secrets["adminUser"]` / `["adminPass"]`; актуальный формат `users.<username>.password`
не был описан нигде. Исправлено 2026-10-01: добавлен раздел в `docs/curated/postgres/pg_user_db.md`,
ссылка в корневом `README.md`, предупреждение в самом гайде.
@@ -0,0 +1,124 @@
# 2026-10-01 — Стенд `TEST_STAND/FPipeGmail`: копия dev-примера, адаптированная под test
> Команда владельца: «`DEV_STAND/FPipeGmail` — это в дев. Надо — сделать такую же папку
> в `TEST_STAND` и соответственно изменить параметры в tf-конфигах, и посмотри чтобы
> не было коллизий — там в стенде есть и эдж и вдц. Найди имя огра».
## Что сделано
Создана `TEST_STAND/FPipeGmail/` — копия `DEV_STAND/FPipeGmail` **без** `.terraform/`,
`terraform.tfstate*`, `.terraform.lock.hcl` (это состояние dev, к test оно не относится).
Состав: `vdc.tf`, `edge.tf`, `modifiers.tf`, `vm.tf`, `shturval.tf`, `variables.tf`,
`outputs.tf`, `provider.tf`, `versions.tf`, `terraform.tfvars` (+ `.example`).
## Найденные данные test-стенда (из API, не из догадок)
| Что | Значение | Откуда |
|---|---|---|
| Организация (vcOrg) | **`NaeelOrg`**, uuid `3f0850f2-3506-4efd-b84b-7270b5027ab5`, `running`, `iaas` | `GET /instances?serviceId=19` |
| ipSpace на организации | `internet-ipv4-v1`, уже выделено **10** IP | `GET /instances/3f0850f2-…` → `vIPConfigure` |
| networkProvider | `snb1` | `GET /instances/e3c9e4f1-…` (существующий vDC `naeel-vdc`) |
| providerVdc | `Intel Broadwell 2.4` | там же |
| storage | `SSD` | там же (`storageConfig`) |
| realm | `sandbox.nubes.ru` | `GET /instances/3f0850f2-…` |
## Изменённые параметры (dev → test)
| Файл | Было (dev) | Стало (test) |
|---|---|---|
| `versions.tf` | `…/nubes-dev/nubes`, `2.0.1` | **`…/nubes-test/nubes`, `3.0.0`** |
| `variables.tf` → `api_endpoint` | `lk-api-gateway-dev…` | **`lk-api-gateway-test…`** |
| `terraform.tfvars` → `organization` | `kontra` | **`NaeelOrg`** |
| `terraform.tfvars` → `api_token` | dev-токен | **test-токен** (`secrets/test.token`) |
| `terraform.tfvars` → `ip_count` | `4` | **`10`**, затем **`12`** (см. раздел про первый apply) |
| `terraform.tfvars` → `vdc_storage_config` | `SATA / 200` | **`SSD / 200`** (в test vDC строят на SSD) |
| `shturval.tf` → `shturval_resource_name` | `shturval-dev1` | **`shturval-test1`** |
| `shturval.tf` → `shturval_cluster_name` | `shturval-dev-01` | **`shturval-test-01`** |
| `shturval.tf` → `shturval_worker_group_name` | `workers-shturval-dev` | **`workers-shturval-test`** |
Не менялись (совпадают с test): `vdc_network_provider=snb1`, `vdc_provider_vdc="Intel Broadwell 2.4"`,
`ip_space_name=internet-ipv4-v1`, DNS/пул Edge, имена `fullpipe-vdc` / `fullpipe-edge` / `fullpipe-vapp-02`.
## Исключение блока ВМ (2026-10-01, по команде владельца)
Файл `TEST_STAND/FPipeGmail/vm.tf` (всё, что относится к vApp и ВМ: переменные, оба ресурса,
выводы) **закомментирован целиком** блочным комментарием `/* … */`.
- Причина: в test инстанс vApp не прошёл валидацию схемы
(«Не удалось произвести валидацию схемы инстанса. Запустите операцию reconcile»).
- Дополнительно: в test разработчику нужно поднять остальную цепочку (vDC → Edge → IP → SNAT → Штурвал),
а ВМ/vApp — позже.
- Как вернуть: удалить первую и последнюю строки блочного комментария в `vm.tf`.
После правки: `terraform fmt -check` — OK, `terraform validate` — Success,
`terraform plan` — **1 to add** (только `nubes_k8s_sthutrval_cluster.shturval`).
Инстансов vApp/ВМ стенда в тенанте нет — все записи `deleted`.
## Первый `apply` в test: ошибки и что с ними делать (2026-10-01)
Создались: `nubes_vc_vdc.vdc` (`fullpipe-vdc`), `nubes_vc_nsxt.edge` (`fullpipe-edge`),
`nubes_vc_org_ip_allocation.org_ip`, `nubes_vc_nsxt_snat.snat`. Упали два ресурса:
| Ресурс | Ошибка | Причина / решение |
|---|---|---|
| `nubes_k8s_sthutrval_cluster.shturval` | операция `61F4FF33-…`: «Кол-во свободных Ip в тенанте `WZ03709-iaas`: 1. Необходимо 2… Перейдите в настройки услуги „Организация в Cloud Director“(3f0850f2-…) → Операция modify» | **квота внешних IP**: на `NaeelOrg` было `count=10`, свободным остался 1 (часть держит кластер `iot-naeel`). Решение: `ip_count` **10 → 12** и применить модификатор |
| `nubes_vapp.vapp` (`fullpipe-vapp-02`) | «Не удалось произвести валидацию схемы инстанса. Запустите операцию `reconcile` у инстанса „Виртуальный каталог ВМ (vApp)“» | инстанс ушёл в `not created`; вероятно плавающая ошибка — проверить после увеличения IP, при повторе сделать `reconcile` |
После `terraform destroy` (сделан владельцем):
| Объект | Состояние | Почему |
|---|---|---|
| `fullpipe-vdc` (21) | `suspended` | `suspend_on_destroy = true` — «заморозка» |
| `fullpipe-edge` (22) | `running` | `keep_on_destroy = true` — destroy эдж не трогает |
| локальный `state` | пуст | — |
Порядок исправления:
```bash
# 1) поднять квоту внешних IP (terraform.tfvars: ip_count="12") — выполняет владелец:
terraform apply -target=nubes_vc_org_ip_allocation.org_ip
# 2) при необходимости — reconcile у vApp в ЛК
# 3) полный цикл (vApp и Штурвал пересоздаются, vDC размораживается, Edge усыновляется):
terraform apply
```
## Проверка коллизий (в test уже есть эдж и vDC)
Занято в test сейчас:
| Услуга | Имена | Статус |
|---|---|---|
| vDC (21) | `naeel-vdc`, `VDC для кластера iot-naeel` | running |
| Edge (22) | `naeel_vc_nsxt`, `Edge для кластера IOT naeel` | running |
| vApp (26) | `vapp-222`, `vm-sless-vapp`, `vm-sless-demo-vapp` | deleted |
| ВМ (28) | `vm-sless`, `vm-sless-1`, `vm-sless-demo` | deleted |
| Штурвал (150) | `naeel-wheel` (deleted), `Кластер Kubernetes [iot-naeel]` | running |
Наши имена (`fullpipe-vdc`, `fullpipe-edge`, `fullpipe-vapp-02`, `web02`, `shturval-test1`)
**свободны** — пересечений нет.
## Проверки конфигурации
```bash
terraform init # установлен nubes-test/nubes 3.0.0 (подпись CB3A0DF161ECC416)
terraform fmt -check -recursive # OK
terraform validate # Success! The configuration is valid.
terraform plan # Plan: 7 to add, 0 to change, 0 to destroy
```
⚠️ `terraform apply` **не выполнялся** — по правилам запускает только владелец.
## Риск, который надо помнить
- `nubes_vc_org_ip_allocation` (модификатор `vIPConfigure`) **перезаписывает массив внешних IP целиком**.
В test на `NaeelOrg` уже выделено 10 адресов (их использует кластер `iot-naeel`), поэтому
`ip_count="10"` — уменьшение сломает чужой стенд.
- В `.gitignore` уже закрыты `terraform.tfvars`, `.terraform/`, `.terraform.lock.hcl`,
`terraform.tfstate*` — в репозиторий попадут только `.tf` и `terraform.tfvars.example`.
## Связанные документы
- `HISTORY/2026-09-25_fullpipe_example_shturval_and_docs.md` — исходный пример FPipeGmail (dev).
- `HISTORY/2026-10-01_release_x_0_0_all_stands.md` — актуальные версии провайдеров стендов.