Добавлены новые возможности для управления файловыми логами в Docker-сервисах: - Обновлены конфигурации для поддержки логов, включая переменные окружения и монтирование директорий. - Документация обновлена для описания новых эндпоинтов и параметров, связанных с логами. - Упрощен доступ к логам через API и интерфейс пользователя. Co-authored-by: Cursor <[email protected]>
130 lines
3.4 KiB
Go
130 lines
3.4 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ed25519"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"evobgp/internal/jobs"
|
|
"evobgp/internal/maintenance"
|
|
"evobgp/internal/pgmonitor"
|
|
"evobgp/internal/runtimelogs"
|
|
"evobgp/internal/store"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// Server implements EvoBGP control-plane HTTP API.
|
|
type Server struct {
|
|
store store.Backend
|
|
pgPool *pgxpool.Pool
|
|
pgMonitor *pgmonitor.Service
|
|
maintConfig *maintenance.ConfigProvider
|
|
maintStats *maintenance.DBStatsProvider
|
|
jobs *jobs.Registry
|
|
bundlePriv ed25519.PrivateKey
|
|
keyResolver *apiKeyResolver
|
|
corsOrigins []string
|
|
cdnHTTP *http.Client
|
|
runtimeLogs *runtimelogs.Service
|
|
mux *http.ServeMux
|
|
}
|
|
|
|
// Options configures the API server.
|
|
type Options struct {
|
|
APIKeys string
|
|
// DatabaseURL enables PostgreSQL-backed store (migrations applied on connect).
|
|
DatabaseURL string
|
|
InsecureDev bool
|
|
SeedDemo bool
|
|
BundleSeedHex string
|
|
CORSAllowedOrigins string
|
|
}
|
|
|
|
// New constructs Server and wiring for async jobs.
|
|
func New(opts Options) (*Server, error) {
|
|
backend, reg, pool, err := BootstrapWorkers(context.Background(), opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var priv ed25519.PrivateKey
|
|
if strings.TrimSpace(opts.BundleSeedHex) != "" {
|
|
seed, err := hex.DecodeString(strings.TrimSpace(opts.BundleSeedHex))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(seed) != ed25519.SeedSize {
|
|
return nil, errors.New("httpapi: BundleSeedHex must decode to 32 bytes")
|
|
}
|
|
priv = ed25519.NewKeyFromSeed(seed)
|
|
} else {
|
|
_, priv, _ = ed25519.GenerateKey(rand.Reader)
|
|
}
|
|
|
|
resolver, err := newAPIKeyResolver(opts.APIKeys, backend)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var pgMon *pgmonitor.Service
|
|
var maintCfg *maintenance.ConfigProvider
|
|
var maintStats *maintenance.DBStatsProvider
|
|
if pool != nil {
|
|
pgMon = pgmonitor.NewService(pool)
|
|
maintCfg = maintenance.NewConfigProvider(backend)
|
|
_ = maintCfg.Reload(context.Background())
|
|
maintStats = maintenance.NewDBStatsProvider(pgMon)
|
|
}
|
|
s := &Server{
|
|
store: backend,
|
|
pgPool: pool,
|
|
pgMonitor: pgMon,
|
|
maintConfig: maintCfg,
|
|
maintStats: maintStats,
|
|
jobs: reg,
|
|
bundlePriv: priv,
|
|
keyResolver: resolver,
|
|
corsOrigins: parseCORSOrigins(opts.CORSAllowedOrigins),
|
|
cdnHTTP: NewCDNHTTPClient(),
|
|
runtimeLogs: runtimelogs.NewService(runtimelogs.ConfigFromEnv()),
|
|
}
|
|
s.mux = http.NewServeMux()
|
|
s.registerRoutes()
|
|
return s, nil
|
|
}
|
|
|
|
// Close releases database resources.
|
|
func (s *Server) Close() {
|
|
if s.pgPool != nil {
|
|
s.pgPool.Close()
|
|
}
|
|
}
|
|
|
|
// Store exposes the backing store (for operators / tests).
|
|
func (s *Server) Store() store.Backend { return s.store }
|
|
|
|
// Jobs exposes the in-process async job registry (for scheduler / evobgp-all).
|
|
func (s *Server) Jobs() *jobs.Registry { return s.jobs }
|
|
|
|
// StartBackground starts PostgreSQL monitoring and maintenance schedulers until ctx is cancelled.
|
|
func (s *Server) StartBackground(ctx context.Context) {
|
|
if s != nil && s.pgPool != nil {
|
|
pgmonitor.StartScheduler(ctx, s.pgPool)
|
|
}
|
|
if s != nil && s.maintConfig != nil && s.jobs != nil {
|
|
maintenance.StartScheduler(ctx, s.maintConfig, func(policyID string, dryRun bool, idem string) {
|
|
key := idem
|
|
_, _, _ = s.jobs.Enqueue("", jobs.KindMaintenancePolicyRun, &key, nil, map[string]any{
|
|
"policy_id": policyID,
|
|
"dry_run": dryRun,
|
|
"trigger": "scheduler",
|
|
})
|
|
}, 30*time.Second)
|
|
}
|
|
}
|