Extract ~200 lines of duplicate database connection code from api/ntpdb/ and monitor/ntpdb/ into common/database/ package. Creates foundation for database consolidation while maintaining zero breaking changes. Files added: - config.go: Unified configuration with package-specific defaults - connector.go: Dynamic connector pattern from Boostport - pool.go: Configurable connection pool management - metrics.go: Optional Prometheus metrics integration - interfaces.go: Shared database interfaces for consistent patterns Key features: - Configuration-driven approach (API: 25/10 connections + metrics, Monitor: 10/5 connections, no metrics) - Optional Prometheus metrics when registerer provided - Backward compatibility via convenience functions - Flexible config file loading (explicit paths + search-based) Dependencies: Added mysql driver and yaml parsing for database configuration.
89 lines
2.0 KiB
Go
89 lines
2.0 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"database/sql/driver"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/go-sql-driver/mysql"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// from https://github.com/Boostport/dynamic-database-config
|
|
|
|
// CreateConnectorFunc is a function that creates a database connector
|
|
type CreateConnectorFunc func() (driver.Connector, error)
|
|
|
|
// Driver implements the sql/driver interface with dynamic configuration
|
|
type Driver struct {
|
|
CreateConnectorFunc CreateConnectorFunc
|
|
}
|
|
|
|
// Driver returns the driver instance
|
|
func (d Driver) Driver() driver.Driver {
|
|
return d
|
|
}
|
|
|
|
// Connect creates a new database connection using the dynamic connector
|
|
func (d Driver) Connect(ctx context.Context) (driver.Conn, error) {
|
|
connector, err := d.CreateConnectorFunc()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error creating connector from function: %w", err)
|
|
}
|
|
|
|
return connector.Connect(ctx)
|
|
}
|
|
|
|
// Open is not supported for dynamic configuration
|
|
func (d Driver) Open(name string) (driver.Conn, error) {
|
|
return nil, errors.New("open is not supported")
|
|
}
|
|
|
|
// createConnector creates a connector function that reads configuration from a file
|
|
func createConnector(configFile string) CreateConnectorFunc {
|
|
return func() (driver.Connector, error) {
|
|
dbFile, err := os.Open(configFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer dbFile.Close()
|
|
|
|
dec := yaml.NewDecoder(dbFile)
|
|
cfg := Config{}
|
|
|
|
err = dec.Decode(&cfg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dsn := cfg.MySQL.DSN
|
|
if len(dsn) == 0 {
|
|
dsn = os.Getenv("DATABASE_DSN")
|
|
if len(dsn) == 0 {
|
|
return nil, fmt.Errorf("dsn config in database.yaml or DATABASE_DSN environment variable required")
|
|
}
|
|
}
|
|
|
|
dbcfg, err := mysql.ParseDSN(dsn)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if user := cfg.MySQL.User; len(user) > 0 {
|
|
dbcfg.User = user
|
|
}
|
|
|
|
if pass := cfg.MySQL.Pass; len(pass) > 0 {
|
|
dbcfg.Passwd = pass
|
|
}
|
|
|
|
if name := cfg.MySQL.DBName; len(name) > 0 {
|
|
dbcfg.DBName = name
|
|
}
|
|
|
|
return mysql.NewConnector(dbcfg)
|
|
}
|
|
}
|