feat(split): data-plane (публичный SQS API) и control-plane (админка/метрики/UI на localhost) — Шаг 2
This commit is contained in:
+49
-28
@@ -28,8 +28,13 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// New — создаёт HTTP router с tenant auth и admin API
|
||||
func New(tenantStore *tenant.TenantStore, adminToken string) http.Handler {
|
||||
// NewDataPlane — публичный SQS API (data-plane): SQS actions, /health, статика, описание.
|
||||
// НЕ содержит админ-консоль, /metrics и /ui — они в control-plane (NewControlPlane).
|
||||
//
|
||||
// Разбиение data-plane/control-plane (Шаг 2): публично доступен только этот роутер.
|
||||
// Пока — два листенера в одном процессе (общее in-memory состояние); отдельные процессы
|
||||
// станут возможны после выноса состояния в Redis (Шаг 3).
|
||||
func NewDataPlane(tenantStore *tenant.TenantStore) http.Handler {
|
||||
r := mux.NewRouter()
|
||||
|
||||
// Fix #3.5: глобальный лимит размера тела HTTP запроса — 3MB
|
||||
@@ -42,37 +47,11 @@ func New(tenantStore *tenant.TenantStore, adminToken string) http.Handler {
|
||||
// /static — логотип, favicon для публичных страниц
|
||||
r.PathPrefix("/static").Handler(ui.StaticHandler()).Methods("GET")
|
||||
|
||||
// /metrics — Prometheus endpoint для Victoria Metrics scrape.
|
||||
// Защищён Bearer admin-токеном: метрики содержат per-tenant данные
|
||||
// (accessKey/число очередей и сообщений), которые нельзя светить наружу.
|
||||
r.Handle("/metrics", metricsAuth(adminToken, promhttp.Handler())).Methods("GET")
|
||||
|
||||
// Страница примеров команд — публично
|
||||
r.HandleFunc("/examples", func(w http.ResponseWriter, req *http.Request) {
|
||||
ui.ExamplesHandler(models.Version).ServeHTTP(w, req)
|
||||
}).Methods("GET")
|
||||
|
||||
// Админ-консоль — статика. Регистрируем ДО admin subrouter,
|
||||
// иначе PathPrefix("/admin") с bearer-auth перехватит GET /admin.
|
||||
r.HandleFunc("/admin", func(w http.ResponseWriter, req *http.Request) {
|
||||
ui.AdminHandler(models.Version).ServeHTTP(w, req)
|
||||
}).Methods("GET")
|
||||
r.HandleFunc("/admin/", func(w http.ResponseWriter, req *http.Request) {
|
||||
ui.AdminHandler(models.Version).ServeHTTP(w, req)
|
||||
}).Methods("GET")
|
||||
|
||||
// Admin API — Bearer token auth, регистрируется через AdminHandler
|
||||
adminHandler := admin.NewHandler(tenantStore, adminToken)
|
||||
adminHandler.RegisterRoutes(r)
|
||||
|
||||
// UI public API — JWT auth, для встроенной console
|
||||
// ВАЖНО: RegisterPublicRoutes ПЕРЕД static handler — иначе PathPrefix("/ui") перехватит /ui/api/*
|
||||
adminHandler.RegisterPublicRoutes(r)
|
||||
|
||||
// UI console — встроенный SPA, публичный доступ
|
||||
// НЕ ловит /ui/api/* — mux сначала проверит более специфичные маршруты выше
|
||||
r.PathPrefix("/ui").Handler(http.StripPrefix("/ui", ui.Handler()))
|
||||
|
||||
// SQS API — tenant auth middleware оборачивает каждый handler отдельно.
|
||||
// r.NewRoute().Subrouter() с Use() некорректно работает в gorilla/mux v1.8.0
|
||||
// при пустом prefix — ответы теряются. Поэтому используем явную обёртку.
|
||||
@@ -94,6 +73,48 @@ func New(tenantStore *tenant.TenantStore, adminToken string) http.Handler {
|
||||
return r
|
||||
}
|
||||
|
||||
// NewControlPlane — админка, метрики и UI (control-plane).
|
||||
// ВАЖНО: этот роутер должен слушать ТОЛЬКО localhost (не проксируется наружу).
|
||||
func NewControlPlane(tenantStore *tenant.TenantStore, adminToken string) http.Handler {
|
||||
r := mux.NewRouter()
|
||||
|
||||
r.Use(requestBodyLimitMiddleware)
|
||||
|
||||
// /health — для проверки control-plane локально
|
||||
r.HandleFunc("/health", health).Methods("GET")
|
||||
|
||||
// /static — нужен UI-консоли (логотип/favicon)
|
||||
r.PathPrefix("/static").Handler(ui.StaticHandler()).Methods("GET")
|
||||
|
||||
// /metrics — Prometheus endpoint для Victoria Metrics scrape.
|
||||
// Защищён Bearer admin-токеном: метрики содержат per-tenant данные
|
||||
// (accessKey/число очередей и сообщений), которые нельзя светить наружу.
|
||||
r.Handle("/metrics", metricsAuth(adminToken, promhttp.Handler())).Methods("GET")
|
||||
|
||||
// Админ-консоль — статика. Регистрируем ДО admin subrouter,
|
||||
// иначе PathPrefix("/admin") с bearer-auth перехватит GET /admin.
|
||||
r.HandleFunc("/admin", func(w http.ResponseWriter, req *http.Request) {
|
||||
ui.AdminHandler(models.Version).ServeHTTP(w, req)
|
||||
}).Methods("GET")
|
||||
r.HandleFunc("/admin/", func(w http.ResponseWriter, req *http.Request) {
|
||||
ui.AdminHandler(models.Version).ServeHTTP(w, req)
|
||||
}).Methods("GET")
|
||||
|
||||
// Admin API — Bearer token auth, регистрируется через AdminHandler
|
||||
adminHandler := admin.NewHandler(tenantStore, adminToken)
|
||||
adminHandler.RegisterRoutes(r)
|
||||
|
||||
// UI public API — JWT auth, для встроенной console
|
||||
// ВАЖНО: RegisterPublicRoutes ПЕРЕД static handler — иначе PathPrefix("/ui") перехватит /ui/api/*
|
||||
adminHandler.RegisterPublicRoutes(r)
|
||||
|
||||
// UI console — встроенный SPA
|
||||
// НЕ ловит /ui/api/* — mux сначала проверит более специфичные маршруты выше
|
||||
r.PathPrefix("/ui").Handler(http.StripPrefix("/ui", ui.Handler()))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// requestBodyLimitMiddleware — ограничивает размер тела HTTP запроса до 3MB.
|
||||
// Защита от OOM при отправке гигантских messages/batch (Fix #3.5).
|
||||
func requestBodyLimitMiddleware(next http.Handler) http.Handler {
|
||||
|
||||
Reference in New Issue
Block a user