Files
EvoBGP/internal/httpapi/server.go
T
Denozordec db75126bea
CI / changes (push) Successful in 9s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 26s
CI / web (push) Successful in 33s
CI / go (push) Successful in 56s
CI / bird2 (push) Successful in 14s
CI / release (push) Successful in 20s
feat(runtime-logs): enhance auto-cleanup features and documentation
Added new endpoints for estimating and executing runtime log auto-cleanup based on tenant settings. Introduced configuration options for auto-cleanup policies, including scheduling and file size limits. Updated the API documentation and UI components to reflect these changes, improving user interaction with runtime log management. Enhanced error handling and added new UI elements for better visibility of audit logs and cleanup actions.
2026-06-12 22:44:39 +07:00

141 lines
4.1 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
runtimeLogsPolicyTenant string
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
// RuntimeLogsPolicyTenant overrides tenant for auto-cleanup scheduler settings (optional).
RuntimeLogsPolicyTenant 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()),
runtimeLogsPolicyTenant: strings.TrimSpace(opts.RuntimeLogsPolicyTenant),
}
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)
}
if s != nil && s.runtimeLogs != nil && s.store != nil {
runtimelogs.StartAutoCleanupScheduler(ctx, runtimelogs.SchedulerDeps{
Service: s.runtimeLogs,
Store: s.store,
PolicyTenant: s.runtimeLogsPolicyTenant,
}, 30*time.Second)
}
}