doc: HISTORY/README-NEW-CHAT.md — полная история для нового чата
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
# tf_registry — Полная история (для нового чата)
|
||||
|
||||
> **Дата**: 2026-08-06
|
||||
> **Проект**: Переписываем Go-реестр Terraform-провайдеров на Python/Flask (managed-сервис Nubes)
|
||||
> **Репозиторий**: `https://gitea.services.ngcloud.ru/Nail/tf_registry.git` (master)
|
||||
> **Управляемый сервис**: `registry` (instanceUid: `309fdf08-8544-407f-96bd-91c8ae70baf8`)
|
||||
> **URL**: `https://registry.pythonk8s.dev.nubes.ru`
|
||||
|
||||
---
|
||||
|
||||
## 1. Контекст
|
||||
|
||||
### Что такое реестр
|
||||
Свой реестр Terraform-провайдеров для `nubes` (кастомный провайдер NGCloud). Работает по HashiCorp Provider Registry Protocol.
|
||||
|
||||
### Как было (Go)
|
||||
- Go-сервер в K8s (личный кластер `iot-naeel`, ВМ `5.172.178.213`)
|
||||
- Домен: `registry.kube5s.ru`
|
||||
- S3: `s3.msk-1.ngcloud.ru`, бакет `terraform-registry`
|
||||
- Креды S3: Secret `s3-credentials` в namespace `terra`
|
||||
|
||||
### Как стало/становится (Flask)
|
||||
- Managed-сервис Nubes `pythonk8s`
|
||||
- Домен: `registry.pythonk8s.dev.nubes.ru`
|
||||
- Тот же S3
|
||||
|
||||
---
|
||||
|
||||
## 2. Структура проекта (как сейчас в master)
|
||||
|
||||
```
|
||||
tf_registry/
|
||||
├── site/
|
||||
│ └── app.py # Flask-приложение (7 роутов)
|
||||
├── requirements.txt # flask, boto3
|
||||
├── secrets/
|
||||
│ └── env.txt # S3-креды + jsonEnv (в .gitignore)
|
||||
├── HISTORY/ # Документация
|
||||
│ ├── plan-sonnet-full.md
|
||||
│ ├── 2026-08-06-plan-review.md
|
||||
│ └── 2026-08-06-first-deploy.md
|
||||
├── .gitignore # secrets/, __pycache__/
|
||||
├── server/ # [LEGACY] Go-код (оставлен для справки)
|
||||
├── operator/ # [LEGACY]
|
||||
├── k8s/ # [LEGACY]
|
||||
├── charts/ # [LEGACY]
|
||||
├── registrykeys/ # [LEGACY] GPG-ключ (устарел!)
|
||||
└── scripts/ # [LEGACY]
|
||||
```
|
||||
|
||||
### Ключевое правило Nubes для Flask
|
||||
```
|
||||
repo/
|
||||
├── requirements.txt
|
||||
└── site/
|
||||
└── app.py ← точка входа, `app.run(host="0.0.0.0", port=5000)`
|
||||
```
|
||||
- **НЕЛЬЗЯ** `site/__init__.py` — конфликтует со stdlib
|
||||
- **НЕЛЬЗЯ** factory pattern — платформа ждёт `app` на уровне модуля
|
||||
- **НЕЛЬЗЯ** `from site.xxx import` — импорт без префикса
|
||||
|
||||
---
|
||||
|
||||
## 3. Эндпоинты (все реализованы)
|
||||
|
||||
| # | Маршрут | Что делает |
|
||||
|---|---|---|
|
||||
| 1 | `GET /.well-known/terraform.json` | `{"providers.v1": "/v1/providers/"}` |
|
||||
| 2 | `GET /v1/providers/{ns}/{name}/versions` | Список версий + платформы из S3 |
|
||||
| 3 | `GET /v1/providers/{ns}/{name}/{ver}/download/{os}/{arch}` | JSON: download_url, shasums, сигнатуры, GPG |
|
||||
| 4 | `GET /v1/proxy?bucket=...&key=...` | Стриминг файла из S3 |
|
||||
| 5 | `GET /docs/{ns}/{name}/{ver}/...` | Статика из S3 (кандидаты ключей) |
|
||||
| 6 | `GET /healthz`, `GET /readyz` | `"ok"` 200 |
|
||||
| 7 | `GET /` | HTML с версией |
|
||||
|
||||
---
|
||||
|
||||
## 4. Конфигурация (jsonEnv в UI)
|
||||
|
||||
```json
|
||||
{
|
||||
"REGISTRY_HOSTNAME": "registry.pythonk8s.dev.nubes.ru",
|
||||
"S3_ENDPOINT": "s3.msk-1.ngcloud.ru",
|
||||
"S3_ACCESS_KEY": "0GLQRD38H4I6RBDB0EWJ",
|
||||
"S3_SECRET_KEY": "eTFibiHmBd96IApj9PYsboTR6OBoD7osxoarHykw",
|
||||
"S3_BUCKET": "terraform-registry"
|
||||
}
|
||||
```
|
||||
|
||||
### Параметры managed-сервиса (appConfiguration)
|
||||
```json
|
||||
{
|
||||
"gitPath": "https://gitea.services.ngcloud.ru/Nail/tf_registry.git",
|
||||
"version": "3.12",
|
||||
"healthPath": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Ключевые детали реализации
|
||||
|
||||
### S3_PREFIX vs HOSTNAME
|
||||
```python
|
||||
HOSTNAME = os.getenv("REGISTRY_HOSTNAME", "localhost:8080") # для URL
|
||||
S3_PREFIX = "registry.kube5s.ru" # для S3-ключей (старый Go-хостнейм!)
|
||||
```
|
||||
S3-ключи лежат под `registry.kube5s.ru/...`, а managed-домен — `registry.pythonk8s.dev.nubes.ru`. Поэтому S3-префикс жёстко `registry.kube5s.ru`.
|
||||
|
||||
### S3-клиент (boto3 + MinIO)
|
||||
```python
|
||||
s3 = boto3.client(
|
||||
"s3",
|
||||
endpoint_url=f"https://{S3_ENDPOINT}",
|
||||
config=Config(signature_version="s3v4"), # важно для MinIO
|
||||
use_ssl=True,
|
||||
)
|
||||
```
|
||||
|
||||
### Пагинация S3
|
||||
Используется `get_paginator("list_objects_v2")` — не `list_objects_v2` напрямую (макс 1000).
|
||||
|
||||
### Платформы
|
||||
Обнаруживаются по имени файла: `_darwin_amd64.zip`, `_linux_amd64.zip`, `_windows_amd64.zip`.
|
||||
|
||||
### GPG-ключи (ДВА — из живого Go-деплоя!)
|
||||
```python
|
||||
GPG_PRIMARY_KEY_ID = "3EC4673EB798238A" # основной (живой деплой)
|
||||
GPG_LEGACY_KEY_ID = "CB3A0DF161ECC416" # старый (из исходников)
|
||||
```
|
||||
Оба возвращаются в `signing_keys.gpg_public_keys`.
|
||||
|
||||
### Docs-кандидаты (1:1 с Go)
|
||||
```
|
||||
/docs/{ns}/{name}/{ver}/style.css
|
||||
1) docs/{ns}/{name}/{ver}/style.css (exact)
|
||||
2) НЕ пробует style.css/index.html (есть расширение .css)
|
||||
3) docs/{ns}/{name}/{ver}/index.html (fallback)
|
||||
|
||||
/docs/{ns}/{name}/{ver}/folder/
|
||||
1) docs/{ns}/{name}/{ver}/folder/ (exact)
|
||||
2) docs/{ns}/{name}/{ver}/folder/index.html (заканчивается на /)
|
||||
3) docs/{ns}/{name}/{ver}/index.html (fallback)
|
||||
```
|
||||
|
||||
### Content-Length при стриминге
|
||||
`head_object` → `ContentLength` → выставляется в заголовках.
|
||||
|
||||
### Порядок роутов
|
||||
`/` — ПОСЛЕДНИЙ, иначе перехватит `/docs/`.
|
||||
|
||||
---
|
||||
|
||||
## 6. История деплоев
|
||||
|
||||
| # | Коммит | Что | Результат |
|
||||
|---|---|---|---|
|
||||
| 1 | `7c2b030` | Минимальный Flask (только `/`) | ❌ Init:Error — gitea приватный |
|
||||
| 2 | — | Репо сделан публичным, редеплой | ✅ `tf_registry v1.0.0` |
|
||||
| 3 | `3fa15cd` | Полный Flask (7 роутов) | ✅ Страница ONLINE, API — пустые versions |
|
||||
| 4 | `a89b1f1` | Fix: S3_PREFIX, GPG, darwin | ⏳ Ожидает редеплоя |
|
||||
| 5 | `f8f6343` | Версия на главной | ⏳ |
|
||||
| 6 | `5ed2948` | HISTORY-документация | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 7. Текущий статус (последний пуш: `5ed2948`)
|
||||
|
||||
- app.py: написан, проверен `py_compile`, все 7 роутов ✅
|
||||
- S3_PREFIX: `registry.kube5s.ru` ✅
|
||||
- GPG: 2 ключа из живого Go ✅
|
||||
- Платформы: darwin + linux + windows ✅
|
||||
- Версия на главной: `v1.0.0` ✅
|
||||
- **НУЖЕН РЕДЕПЛОЙ** через UI → проверить `versions` и `download`
|
||||
|
||||
---
|
||||
|
||||
## 8. Что дальше
|
||||
|
||||
1. Редеплой через UI
|
||||
2. Проверить `curl /.well-known/terraform.json`
|
||||
3. Проверить `curl /v1/providers/nubes-test/nubes/versions` — должны быть версии
|
||||
4. Проверить `curl /v1/providers/nubes-test/nubes/5.1.16/download/linux/amd64` — shasum не пустой
|
||||
5. `terraform init` с `source = "registry.pythonk8s.dev.nubes.ru/nubes-test/nubes"`
|
||||
|
||||
---
|
||||
|
||||
## 9. Как продолжить в новом чате
|
||||
|
||||
1. Открыть workspace `~/tf_registry`
|
||||
2. Прочитать этот файл
|
||||
3. `git pull` (на всякий случай)
|
||||
4. Сказать: «Продолжаем tf_registry Flask-реестр. Контекст в HISTORY/README-NEW-CHAT.md»
|
||||
|
||||
---
|
||||
|
||||
## 10. Правила проекта
|
||||
|
||||
- После каждого коммита → сразу push
|
||||
- Перед каждым коммитом → `python3 -m py_compile site/app.py`
|
||||
- `gitPath` в UI: `https://gitea.services.ngcloud.ru/Nail/tf_registry.git`
|
||||
- Репо должен быть публичным (или вшить токен в gitPath)
|
||||
- Кубер — только через ВМ: `ssh naeel@5.172.178.213`
|
||||
- Не удалять Go-файлы — оставлены для справки
|
||||
- S3_PREFIX = `registry.kube5s.ru` (НЕ managed-домен!)
|
||||
Reference in New Issue
Block a user