Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var Cmd = &cobra.Command{ Use: "serve", Aliases: []string{"run"}, Short: "Starts the DRS Object API server", Run: func(cmd *cobra.Command, args []string) { logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) slog.SetDefault(logger) fatal := func(msg string, args ...any) { logger.Error(msg, args...) os.Exit(1) } cfg, err := config.LoadConfig(configFile) if err != nil { fatal("failed to load config", "err", err) } if cfg.Auth.Mode == config.AuthModeGen3 && cfg.Database.Postgres == nil && !isMockAuthEnabled() { fatal("auth.mode=gen3 requires postgres database") } // Init DB var database db.DatabaseInterface var errDb error if cfg.Database.Sqlite != nil { dbPath := cfg.Database.Sqlite.File if dbPath == "" { dbPath = "drs.db" cfg.Database.Sqlite.File = dbPath } logger.Info("initializing sqlite database", "file", dbPath) database, errDb = sqlite.NewSqliteDB(dbPath) } else if cfg.Database.Postgres != nil { dsn := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s", cfg.Database.Postgres.User, cfg.Database.Postgres.Password, cfg.Database.Postgres.Host, cfg.Database.Postgres.Port, cfg.Database.Postgres.Database, cfg.Database.Postgres.SSLMode, ) logger.Info("initializing postgres database", "host", cfg.Database.Postgres.Host, "database", cfg.Database.Postgres.Database) database, errDb = postgres.NewPostgresDB(dsn) } else { fatal("no database configuration provided") } if errDb != nil { fatal("failed to initialize database", "err", errDb) } applyCredentialEncryptionConfig(cfg) if len(cfg.S3Credentials) > 0 { encryptionEnabled, encErr := crypto.CredentialEncryptionEnabled() if encErr != nil { fatal("invalid credential encryption configuration", "env", crypto.CredentialMasterKeyEnv, "err", encErr) } if !encryptionEnabled { fatal("s3 credential encryption key is required", "env", crypto.CredentialMasterKeyEnv) } logger.Info("loading configured s3 credentials", "count", len(cfg.S3Credentials)) for _, c := range cfg.S3Credentials { cred := &models.S3Credential{ Bucket: c.Bucket, Provider: c.Provider, Region: c.Region, AccessKey: c.AccessKey, SecretKey: c.SecretKey, Endpoint: c.Endpoint, BillingLogBucket: c.BillingLogBucket, BillingLogPrefix: c.BillingLogPrefix, } if c.ProviderBillingLogsEnabled() { if err := metricapi.ValidateProviderTransferLogSource(cmd.Context(), *cred); err != nil { fatal("invalid provider billing log configuration", "bucket", c.Bucket, "err", err) } } else { logger.Info("provider billing log validation disabled", "bucket", c.Bucket, "provider", c.Provider) } if err := database.SaveS3Credential(cmd.Context(), cred); err != nil { logger.Error("failed to save s3 credential", "bucket", c.Bucket, "err", err) } } } needsUrlManager := cfg.Routes.Ga4gh || cfg.Routes.Internal || cfg.Routes.LFS var uM *urlmanager.Manager if needsUrlManager { uM = urlmanager.NewManager(database, cfg.Signing) uM.RegisterSigner(common.S3Provider, s3.NewS3Signer(database)) uM.RegisterSigner(common.GCSProvider, gcs.NewGCSSigner(database)) uM.RegisterSigner(common.AzureProvider, azure.NewAzureSigner(database)) fSigner, fErr := file.NewFileSigner("/") if fErr == nil { uM.RegisterSigner(common.FileProvider, fSigner) } else { logger.Warn("failed to initialize file signer", "err", fErr) } } om := core.NewObjectManager(database, uM) app := fiber.New(fiber.Config{ ReadTimeout: 30 * time.Second, WriteTimeout: 120 * time.Second, IdleTimeout: 120 * time.Second, ReadBufferSize: 64 * 1024, AppName: "Syfon DRS Server", }) app.Use(recover.New()) slogLogger := logger authzMiddleware := middleware.NewAuthzMiddleware( slogLogger, cfg.Auth.Mode, cfg.Auth.Basic.Username, cfg.Auth.Basic.Password, ) requestIDMiddleware := middleware.NewRequestIDMiddleware(slogLogger) rt := &serverRuntime{ app: app, cfg: cfg, database: database, om: om, uM: uM, authzMiddleware: authzMiddleware, requestIDMiddleware: requestIDMiddleware, } applyServerOptions(rt, buildServerOptions(cfg)...) addr := fmt.Sprintf(":%d", cfg.Port) logger.Info("server starting", "addr", addr) errCh := make(chan error, 1) go func() { if err := app.Listen(addr); err != nil { errCh <- err } }() sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) defer signal.Stop(sigCh) select { case err := <-errCh: fatal("server listen failed", "err", err) case sig := <-sigCh: logger.Info("shutdown signal received", "signal", sig.String()) case <-cmd.Context().Done(): logger.Info("shutdown requested by context cancellation") } shutdownCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() if err := app.ShutdownWithContext(shutdownCtx); err != nil { fatal("server shutdown failed", "err", err) } logger.Info("server shutdown complete") }, }
Functions ¶
This section is empty.
Types ¶
type ServerOption ¶ added in v0.2.0
type ServerOption func(*serverRuntime)
func WithDocsRoutes ¶ added in v0.2.0
func WithDocsRoutes() ServerOption
func WithGa4ghRoutes ¶ added in v0.2.0
func WithGa4ghRoutes() ServerOption
func WithHealthzRoute ¶ added in v0.2.0
func WithHealthzRoute() ServerOption
func WithInternalRoutes ¶ added in v0.2.0
func WithInternalRoutes() ServerOption
func WithLFSRoutes ¶ added in v0.2.0
func WithLFSRoutes() ServerOption
func WithMetricsRoutes ¶ added in v0.2.0
func WithMetricsRoutes() ServerOption
Click to show internal directories.
Click to hide internal directories.