Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ flight_port: 8815
flight_session_idle_ttl: "10m"
flight_session_reap_interval: "1m"
flight_handle_idle_ttl: "15m"
flight_session_token_ttl: "1h"
data_dir: "./data"

tls:
Expand Down Expand Up @@ -176,6 +177,7 @@ Run with config file:
| `DUCKGRES_FLIGHT_SESSION_IDLE_TTL` | Flight auth session idle TTL | `10m` |
| `DUCKGRES_FLIGHT_SESSION_REAP_INTERVAL` | Flight auth session reap interval | `1m` |
| `DUCKGRES_FLIGHT_HANDLE_IDLE_TTL` | Flight prepared/query handle idle TTL | `15m` |
| `DUCKGRES_FLIGHT_SESSION_TOKEN_TTL` | Flight issued session token absolute TTL | `1h` |
| `DUCKGRES_DATA_DIR` | Directory for DuckDB files | `./data` |
| `DUCKGRES_CERT` | TLS certificate file | `./certs/server.crt` |
| `DUCKGRES_KEY` | TLS private key file | `./certs/server.key` |
Expand Down Expand Up @@ -221,6 +223,7 @@ Options:
-flight-session-idle-ttl string Flight auth session idle TTL (e.g., '10m')
-flight-session-reap-interval string Flight auth session reap interval (e.g., '1m')
-flight-handle-idle-ttl string Flight prepared/query handle idle TTL (e.g., '15m')
-flight-session-token-ttl string Flight issued session token absolute TTL (e.g., '1h')
-data-dir string Directory for DuckDB files
-cert string TLS certificate file
-key string TLS private key file
Expand Down
23 changes: 23 additions & 0 deletions config_resolution.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type configCLIInputs struct {
FlightSessionIdleTTL string
FlightSessionReapInterval string
FlightHandleIdleTTL string
FlightSessionTokenTTL string
DataDir string
CertFile string
KeyFile string
Expand Down Expand Up @@ -44,6 +45,7 @@ func defaultServerConfig() server.Config {
FlightSessionIdleTTL: 10 * time.Minute,
FlightSessionReapInterval: 1 * time.Minute,
FlightHandleIdleTTL: 15 * time.Minute,
FlightSessionTokenTTL: 1 * time.Hour,
DataDir: "./data",
TLSCertFile: "./certs/server.crt",
TLSKeyFile: "./certs/server.key",
Expand Down Expand Up @@ -98,6 +100,13 @@ func resolveEffectiveConfig(fileCfg *FileConfig, cli configCLIInputs, getenv fun
warn("Invalid flight_handle_idle_ttl duration: " + err.Error())
}
}
if fileCfg.FlightSessionTokenTTL != "" {
if d, err := time.ParseDuration(fileCfg.FlightSessionTokenTTL); err == nil {
cfg.FlightSessionTokenTTL = d
} else {
warn("Invalid flight_session_token_ttl duration: " + err.Error())
}
}
if fileCfg.DataDir != "" {
cfg.DataDir = fileCfg.DataDir
}
Expand Down Expand Up @@ -251,6 +260,13 @@ func resolveEffectiveConfig(fileCfg *FileConfig, cli configCLIInputs, getenv fun
warn("Invalid DUCKGRES_FLIGHT_HANDLE_IDLE_TTL duration: " + err.Error())
}
}
if v := getenv("DUCKGRES_FLIGHT_SESSION_TOKEN_TTL"); v != "" {
if d, err := time.ParseDuration(v); err == nil {
cfg.FlightSessionTokenTTL = d
} else {
warn("Invalid DUCKGRES_FLIGHT_SESSION_TOKEN_TTL duration: " + err.Error())
}
}
if v := getenv("DUCKGRES_DATA_DIR"); v != "" {
cfg.DataDir = v
}
Expand Down Expand Up @@ -385,6 +401,13 @@ func resolveEffectiveConfig(fileCfg *FileConfig, cli configCLIInputs, getenv fun
warn("Invalid --flight-handle-idle-ttl duration: " + err.Error())
}
}
if cli.Set["flight-session-token-ttl"] {
if d, err := time.ParseDuration(cli.FlightSessionTokenTTL); err == nil {
cfg.FlightSessionTokenTTL = d
} else {
warn("Invalid --flight-session-token-ttl duration: " + err.Error())
}
}
if cli.Set["data-dir"] {
cfg.DataDir = cli.DataDir
}
Expand Down
1 change: 1 addition & 0 deletions controlplane/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ func RunControlPlane(cfg ControlPlaneConfig) {
SessionIdleTTL: cfg.FlightSessionIdleTTL,
SessionReapTick: cfg.FlightSessionReapInterval,
HandleIdleTTL: cfg.FlightHandleIdleTTL,
SessionTokenTTL: cfg.FlightSessionTokenTTL,
})
if err != nil {
slog.Error("Failed to initialize Flight ingress.", "error", err)
Expand Down
4 changes: 4 additions & 0 deletions duckgres.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ port: 5432
# Control-plane Arrow Flight SQL ingress (optional)
# 0 or omitted disables Flight ingress.
# flight_port: 8815
# flight_session_idle_ttl: "10m"
# flight_session_reap_interval: "1m"
# flight_handle_idle_ttl: "15m"
# flight_session_token_ttl: "1h"

# Directory for DuckDB database files (one per user)
data_dir: "./data"
Expand Down
4 changes: 4 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type FileConfig struct {
FlightSessionIdleTTL string `yaml:"flight_session_idle_ttl"` // e.g., "10m"
FlightSessionReapInterval string `yaml:"flight_session_reap_interval"` // e.g., "1m"
FlightHandleIdleTTL string `yaml:"flight_handle_idle_ttl"` // e.g., "15m"
FlightSessionTokenTTL string `yaml:"flight_session_token_ttl"` // e.g., "1h"
DataDir string `yaml:"data_dir"`
TLS TLSConfig `yaml:"tls"`
Users map[string]string `yaml:"users"`
Expand Down Expand Up @@ -145,6 +146,7 @@ func main() {
flightSessionIdleTTL := flag.String("flight-session-idle-ttl", "", "Flight auth session idle TTL (e.g., '10m') (env: DUCKGRES_FLIGHT_SESSION_IDLE_TTL)")
flightSessionReapInterval := flag.String("flight-session-reap-interval", "", "Flight auth session reap interval (e.g., '1m') (env: DUCKGRES_FLIGHT_SESSION_REAP_INTERVAL)")
flightHandleIdleTTL := flag.String("flight-handle-idle-ttl", "", "Flight prepared/query handle idle TTL (e.g., '15m') (env: DUCKGRES_FLIGHT_HANDLE_IDLE_TTL)")
flightSessionTokenTTL := flag.String("flight-session-token-ttl", "", "Flight issued session token absolute TTL (e.g., '1h') (env: DUCKGRES_FLIGHT_SESSION_TOKEN_TTL)")
dataDir := flag.String("data-dir", "", "Directory for DuckDB files (env: DUCKGRES_DATA_DIR)")
certFile := flag.String("cert", "", "TLS certificate file (env: DUCKGRES_CERT)")
keyFile := flag.String("key", "", "TLS private key file (env: DUCKGRES_KEY)")
Expand Down Expand Up @@ -189,6 +191,7 @@ func main() {
fmt.Fprintf(os.Stderr, " DUCKGRES_FLIGHT_SESSION_IDLE_TTL Flight auth session idle TTL (default: 10m)\n")
fmt.Fprintf(os.Stderr, " DUCKGRES_FLIGHT_SESSION_REAP_INTERVAL Flight auth session reap interval (default: 1m)\n")
fmt.Fprintf(os.Stderr, " DUCKGRES_FLIGHT_HANDLE_IDLE_TTL Flight prepared/query handle idle TTL (default: 15m)\n")
fmt.Fprintf(os.Stderr, " DUCKGRES_FLIGHT_SESSION_TOKEN_TTL Flight issued session token absolute TTL (default: 1h)\n")
fmt.Fprintf(os.Stderr, " DUCKGRES_DATA_DIR Directory for DuckDB files (default: ./data)\n")
fmt.Fprintf(os.Stderr, " DUCKGRES_CERT TLS certificate file (default: ./certs/server.crt)\n")
fmt.Fprintf(os.Stderr, " DUCKGRES_KEY TLS private key file (default: ./certs/server.key)\n")
Expand Down Expand Up @@ -271,6 +274,7 @@ func main() {
FlightSessionIdleTTL: *flightSessionIdleTTL,
FlightSessionReapInterval: *flightSessionReapInterval,
FlightHandleIdleTTL: *flightHandleIdleTTL,
FlightSessionTokenTTL: *flightSessionTokenTTL,
DataDir: *dataDir,
CertFile: *certFile,
KeyFile: *keyFile,
Expand Down
15 changes: 15 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,23 +375,27 @@ func TestResolveEffectiveConfigFlightIngressDurations(t *testing.T) {
FlightSessionIdleTTL: "7m",
FlightSessionReapInterval: "45s",
FlightHandleIdleTTL: "3m",
FlightSessionTokenTTL: "2h",
}

env := map[string]string{
"DUCKGRES_FLIGHT_SESSION_IDLE_TTL": "9m",
"DUCKGRES_FLIGHT_SESSION_REAP_INTERVAL": "30s",
"DUCKGRES_FLIGHT_HANDLE_IDLE_TTL": "4m",
"DUCKGRES_FLIGHT_SESSION_TOKEN_TTL": "90m",
}

resolved := resolveEffectiveConfig(fileCfg, configCLIInputs{
Set: map[string]bool{
"flight-session-idle-ttl": true,
"flight-session-reap-interval": true,
"flight-handle-idle-ttl": true,
"flight-session-token-ttl": true,
},
FlightSessionIdleTTL: "11m",
FlightSessionReapInterval: "15s",
FlightHandleIdleTTL: "5m",
FlightSessionTokenTTL: "75m",
}, envFromMap(env), nil)

if resolved.Server.FlightSessionIdleTTL != 11*time.Minute {
Expand All @@ -403,13 +407,17 @@ func TestResolveEffectiveConfigFlightIngressDurations(t *testing.T) {
if resolved.Server.FlightHandleIdleTTL != 5*time.Minute {
t.Fatalf("expected CLI flight_handle_idle_ttl, got %s", resolved.Server.FlightHandleIdleTTL)
}
if resolved.Server.FlightSessionTokenTTL != 75*time.Minute {
t.Fatalf("expected CLI flight_session_token_ttl, got %s", resolved.Server.FlightSessionTokenTTL)
}
}

func TestResolveEffectiveConfigFlightIngressDurationsFromFile(t *testing.T) {
fileCfg := &FileConfig{
FlightSessionIdleTTL: "7m",
FlightSessionReapInterval: "45s",
FlightHandleIdleTTL: "3m",
FlightSessionTokenTTL: "2h",
}

resolved := resolveEffectiveConfig(fileCfg, configCLIInputs{}, envFromMap(nil), nil)
Expand All @@ -423,13 +431,17 @@ func TestResolveEffectiveConfigFlightIngressDurationsFromFile(t *testing.T) {
if resolved.Server.FlightHandleIdleTTL != 3*time.Minute {
t.Fatalf("expected file flight_handle_idle_ttl, got %s", resolved.Server.FlightHandleIdleTTL)
}
if resolved.Server.FlightSessionTokenTTL != 2*time.Hour {
t.Fatalf("expected file flight_session_token_ttl, got %s", resolved.Server.FlightSessionTokenTTL)
}
}

func TestResolveEffectiveConfigFlightIngressDurationsFromEnv(t *testing.T) {
env := map[string]string{
"DUCKGRES_FLIGHT_SESSION_IDLE_TTL": "9m",
"DUCKGRES_FLIGHT_SESSION_REAP_INTERVAL": "30s",
"DUCKGRES_FLIGHT_HANDLE_IDLE_TTL": "4m",
"DUCKGRES_FLIGHT_SESSION_TOKEN_TTL": "30m",
}

resolved := resolveEffectiveConfig(nil, configCLIInputs{}, envFromMap(env), nil)
Expand All @@ -443,6 +455,9 @@ func TestResolveEffectiveConfigFlightIngressDurationsFromEnv(t *testing.T) {
if resolved.Server.FlightHandleIdleTTL != 4*time.Minute {
t.Fatalf("expected env flight_handle_idle_ttl, got %s", resolved.Server.FlightHandleIdleTTL)
}
if resolved.Server.FlightSessionTokenTTL != 30*time.Minute {
t.Fatalf("expected env flight_session_token_ttl, got %s", resolved.Server.FlightSessionTokenTTL)
}
}

func TestResolveEffectiveConfigInvalidFlightPortEnv(t *testing.T) {
Expand Down
Loading