Database Package (internal/database/): - Database interface abstraction for multiple backends - SQLite implementation with pure Go driver (no CGO) - PostgreSQL implementation with connection pooling - Factory pattern for creating database from config - Tiered retention with automatic aggregation: - Raw metrics: 24h (5s resolution) - 1-minute aggregation: 7 days - 5-minute aggregation: 30 days - Hourly aggregation: 1 year Schema includes: - agents: registration, status, certificates - users: local + LDAP authentication - roles: RBAC with permissions JSON - sessions: token-based authentication - metrics_*: time-series with aggregation - alerts: triggered alerts with acknowledgment Configuration Updates: - DatabaseConfig with SQLite path and PostgreSQL settings - RetentionConfig for customizing data retention - Environment variables: TYTO_DB_*, TYTO_DB_CONNECTION_STRING - Default SQLite at /var/lib/tyto/tyto.db 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
91 lines
2.2 KiB
Go
91 lines
2.2 KiB
Go
// Package database provides database factory for creating the appropriate backend.
|
|
package database
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"tyto/internal/config"
|
|
)
|
|
|
|
// New creates a new database connection based on configuration.
|
|
func New(cfg *config.DatabaseConfig) (Database, error) {
|
|
retention := DefaultRetentionConfig()
|
|
|
|
// Override retention from config if provided
|
|
if cfg.Retention.RawRetention > 0 {
|
|
retention.RawRetention = cfg.Retention.RawRetention
|
|
}
|
|
if cfg.Retention.OneMinuteRetention > 0 {
|
|
retention.OneMinuteRetention = cfg.Retention.OneMinuteRetention
|
|
}
|
|
if cfg.Retention.FiveMinuteRetention > 0 {
|
|
retention.FiveMinuteRetention = cfg.Retention.FiveMinuteRetention
|
|
}
|
|
if cfg.Retention.HourlyRetention > 0 {
|
|
retention.HourlyRetention = cfg.Retention.HourlyRetention
|
|
}
|
|
|
|
switch cfg.Type {
|
|
case "sqlite", "":
|
|
return newSQLiteFromConfig(cfg, retention)
|
|
case "postgres", "postgresql":
|
|
return newPostgresFromConfig(cfg, retention)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", cfg.Type)
|
|
}
|
|
}
|
|
|
|
func newSQLiteFromConfig(cfg *config.DatabaseConfig, retention RetentionConfig) (*SQLiteDB, error) {
|
|
path := cfg.Path
|
|
if path == "" {
|
|
path = "tyto.db"
|
|
}
|
|
|
|
// Ensure directory exists
|
|
dir := filepath.Dir(path)
|
|
if dir != "" && dir != "." {
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
return nil, fmt.Errorf("create database directory: %w", err)
|
|
}
|
|
}
|
|
|
|
db, err := NewSQLiteDB(path, retention)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Run migrations
|
|
if err := db.Migrate(); err != nil {
|
|
db.Close()
|
|
return nil, fmt.Errorf("migrate: %w", err)
|
|
}
|
|
|
|
return db, nil
|
|
}
|
|
|
|
func newPostgresFromConfig(cfg *config.DatabaseConfig, retention RetentionConfig) (*PostgresDB, error) {
|
|
connStr := cfg.ConnectionString
|
|
if connStr == "" {
|
|
// Build connection string from individual fields
|
|
connStr = fmt.Sprintf(
|
|
"host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
|
|
cfg.Host, cfg.Port, cfg.User, cfg.Password, cfg.Database, cfg.SSLMode,
|
|
)
|
|
}
|
|
|
|
db, err := NewPostgresDB(connStr, retention)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Run migrations
|
|
if err := db.Migrate(); err != nil {
|
|
db.Close()
|
|
return nil, fmt.Errorf("migrate: %w", err)
|
|
}
|
|
|
|
return db, nil
|
|
}
|