v1.0.0 — минимальный Flask (site/app.py), проверка managed-сервиса
This commit is contained in:
@@ -0,0 +1,91 @@
|
|||||||
|
# 2026-08-06 — Ревизия плана Flask-реестра
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
Переписываем Go-реестр (`server/main.go`) на Python/Flask для managed-сервиса в облаке.
|
||||||
|
Логика 1:1 — те же эндпоинты, та же S3-структура, тот же GPG-ключ.
|
||||||
|
|
||||||
|
## Файлы прочитаны
|
||||||
|
|
||||||
|
| Файл | Строки | Что |
|
||||||
|
|---|---|---|
|
||||||
|
| `server/main.go` | 1-289 | Весь HTTP-сервер: 7 роутов, S3, GPG |
|
||||||
|
| `server/docs.go` | 1-200 | Docs-сервер с кандидатами ключей |
|
||||||
|
| `server/gpg_key.go` | 1-50 | Прокси к `registrykeys` пакету |
|
||||||
|
| `registrykeys/public_key.go` | 1-50 | Константы KeyID + ASCIIArmor |
|
||||||
|
| `CHAT_SUMMARY_2026-08-06.md` | 1-100 | Контекст: архитектура, S3-структура, ENV |
|
||||||
|
|
||||||
|
## План (из plan.md) — TL;DR
|
||||||
|
|
||||||
|
- **Фаза 1**: git checkout -b golang → удалить Go-код из master
|
||||||
|
- **Фаза 2**: `app.py` (~250-300 строк Flask) + `requirements.txt` (flask, boto3)
|
||||||
|
- **Фаза 3**: py_compile → деплой → curl-проверки → terraform init
|
||||||
|
|
||||||
|
### Эндпоинты (из Go-кода):
|
||||||
|
|
||||||
|
| URL | Ответ |
|
||||||
|
|---|---|
|
||||||
|
| `GET /.well-known/terraform.json` | `{"providers.v1": "/v1/providers/"}` |
|
||||||
|
| `GET /v1/providers/{ns}/{name}/versions` | JSON: id, versions[], warnings[] |
|
||||||
|
| `GET /v1/providers/{ns}/{name}/{ver}/download/{os}/{arch}` | JSON: download_url, shasums_url, sig_url, shasum, signing_keys |
|
||||||
|
| `GET /v1/proxy?bucket=...&key=...` | Стриминг файла из S3 |
|
||||||
|
| `GET /docs/{ns}/{name}/{ver}/...` | Статика из S3 (кандидаты ключей) |
|
||||||
|
| `GET /healthz` | `"ok"` 200 |
|
||||||
|
| `GET /readyz` | `"ok"` 200 |
|
||||||
|
| `GET /` | HTML-страница "ONLINE" |
|
||||||
|
|
||||||
|
### S3-ключи:
|
||||||
|
|
||||||
|
```
|
||||||
|
{hostname}/{namespace}/{name}/{version}/terraform-provider-{name}_{ver}_{os}_{arch}.zip
|
||||||
|
{hostname}/{namespace}/{name}/{version}/terraform-provider-{name}_{ver}_SHA256SUMS
|
||||||
|
{hostname}/{namespace}/{name}/{version}/terraform-provider-{name}_{ver}_SHA256SUMS.sig
|
||||||
|
docs/{namespace}/{name}/{version}/{path}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ENV-переменные:
|
||||||
|
- `REGISTRY_HOSTNAME` (default: `localhost:8080`)
|
||||||
|
- `S3_ENDPOINT`
|
||||||
|
- `S3_ACCESS_KEY`
|
||||||
|
- `S3_SECRET_KEY`
|
||||||
|
- `S3_BUCKET` (default: `terraform-registry`)
|
||||||
|
|
||||||
|
## 6 замечаний к плану
|
||||||
|
|
||||||
|
### 1. ⚠️ S3-пагинация (ВАЖНО)
|
||||||
|
Go: `ListObjects` → канал с авто-пагинацией (все объекты).
|
||||||
|
boto3: `list_objects_v2` → макс 1000 за раз.
|
||||||
|
**Надо:** `Paginator` или цикл с `ContinuationToken`.
|
||||||
|
|
||||||
|
### 2. Docs-кандидаты (точность)
|
||||||
|
Go-логика чуть точнее, чем описано в плане:
|
||||||
|
- `rest` пустой → только `index.html`
|
||||||
|
- `rest` не пустой: exact → (если `/` на конце ИЛИ нет расширения → `{rest}/index.html`) → `index.html`
|
||||||
|
- Для `.css`/`.js` НЕ пробуется `{rest}/index.html`
|
||||||
|
|
||||||
|
### 3. Content-Length при стриминге
|
||||||
|
Go ставит через `obj.Stat()`. Flask `stream_with_context` — нет.
|
||||||
|
**Надо:** `head_object` → взять `ContentLength` → выставить вручную.
|
||||||
|
|
||||||
|
### 4. boto3 + MinIO
|
||||||
|
```python
|
||||||
|
boto3.client('s3',
|
||||||
|
endpoint_url=f'https://{s3_endpoint}',
|
||||||
|
use_ssl=True,
|
||||||
|
config=Config(signature_version='s3v4')
|
||||||
|
)
|
||||||
|
```
|
||||||
|
Без `s3v4` могут быть ошибки подписи на MinIO.
|
||||||
|
|
||||||
|
### 5. /readyz
|
||||||
|
Go: комментарий «Проверить S3», но реально просто `"ok"`.
|
||||||
|
Делать 1:1 → просто `"ok"`.
|
||||||
|
|
||||||
|
### 6. Порядок роутов во Flask
|
||||||
|
Flask матчит сверху вниз. `/` должен быть последним, чтобы не перехватить `/docs/`.
|
||||||
|
|
||||||
|
## Решения (подтверждены)
|
||||||
|
- GPG: только константа, без python-gnupg ✅
|
||||||
|
- Прокси: `?bucket=&key=` (НЕ `?url=`) ✅
|
||||||
|
- Платформы: только `linux_amd64` + `windows_amd64` ✅
|
||||||
|
- Домен: `registry.pythonk8s.dev.nubes.ru` ✅
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
flask
|
||||||
Binary file not shown.
+14
@@ -0,0 +1,14 @@
|
|||||||
|
VERSION = "1.0.0"
|
||||||
|
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
return f"<h1>tf_registry v{VERSION}</h1>"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(host="0.0.0.0", port=5000)
|
||||||
Reference in New Issue
Block a user