package config import ( "fmt" "os" "slices" "strconv" ) const ( StorageDriverLocal = "local" StorageDriverS3 = "s3" DefaultStorageDriver = StorageDriverLocal DefaultS3Region = "us-east-1" DefaultS3PathStyle = "false" DefaultS3TLS = "true" EnvStorageDriver = "STORAGE_DRIVER" envS3Bucket = "S3_BUCKET" envS3Region = "S3_REGION" envS3Endpoint = "S3_ENDPOINT" envS3AccessKeyID = "S3_ACCESS_KEY_ID" envS3SecretKey = "S3_SECRET_ACCESS_KEY" envS3KeyPrefix = "S3_KEY_PREFIX" envS3PathStyle = "S3_PATH_STYLE" envS3TLS = "S3_TLS" ) var s3RequiredEnvVars = []string{envS3Bucket} type S3Settings struct { Bucket string Region string Endpoint string AccessKeyID string SecretAccessKey string KeyPrefix string PathStyle bool TLS bool } type StorageSettings struct { Driver string S3 S3Settings } func StorageRequiredEnvVars(driver string) []string { if driver == StorageDriverS3 { return slices.Clone(s3RequiredEnvVars) } return nil } func storageSettingsFromEnv() (StorageSettings, error) { driver := envOrDefault(EnvStorageDriver, DefaultStorageDriver) switch driver { case StorageDriverLocal: return StorageSettings{Driver: driver}, nil case StorageDriverS3: s3, err := s3SettingsFromEnv() if err != nil { return StorageSettings{}, err } return StorageSettings{Driver: driver, S3: s3}, nil default: return StorageSettings{}, fmt.Errorf("unsupported storage driver %q", driver) } } func s3SettingsFromEnv() (S3Settings, error) { if err := MissingEnvVarError(s3RequiredEnvVars, nonEmptyEnvLookup); err != nil { return S3Settings{}, err } accessKeyID := os.Getenv(envS3AccessKeyID) secretKey := os.Getenv(envS3SecretKey) if accessKeyID != "" && secretKey == "" { return S3Settings{}, fmt.Errorf("Environment variable %s is not set (it is required when %s is set)", envS3SecretKey, envS3AccessKeyID) } if secretKey != "" && accessKeyID == "" { return S3Settings{}, fmt.Errorf("Environment variable %s is not set (it is required when %s is set)", envS3AccessKeyID, envS3SecretKey) } pathStyle, err := boolEnv(envS3PathStyle, DefaultS3PathStyle) if err != nil { return S3Settings{}, err } tls, err := boolEnv(envS3TLS, DefaultS3TLS) if err != nil { return S3Settings{}, err } return S3Settings{ Bucket: os.Getenv(envS3Bucket), Region: envOrDefault(envS3Region, DefaultS3Region), Endpoint: os.Getenv(envS3Endpoint), AccessKeyID: accessKeyID, SecretAccessKey: secretKey, KeyPrefix: os.Getenv(envS3KeyPrefix), PathStyle: pathStyle, TLS: tls, }, nil } func nonEmptyEnvLookup(name string) (string, bool) { value := os.Getenv(name) return value, value != "" } func boolEnv(name string, fallback string) (bool, error) { raw := envOrDefault(name, fallback) value, err := strconv.ParseBool(raw) if err != nil { return false, fmt.Errorf("%s must be true or false, got %q", name, raw) } return value, nil }