fetch_ml/internal/config/smart_defaults.go
Jeremie Fraeys 803677be57 feat: implement Go backend with comprehensive API and internal packages
- Add API server with WebSocket support and REST endpoints
- Implement authentication system with API keys and permissions
- Add task queue system with Redis backend and error handling
- Include storage layer with database migrations and schemas
- Add comprehensive logging, metrics, and telemetry
- Implement security middleware and network utilities
- Add experiment management and container orchestration
- Include configuration management with smart defaults
2025-12-04 16:53:53 -05:00

222 lines
5.6 KiB
Go

package config
import (
"os"
"path/filepath"
"runtime"
"strings"
)
// EnvironmentProfile represents the deployment environment
type EnvironmentProfile int
const (
ProfileLocal EnvironmentProfile = iota
ProfileContainer
ProfileCI
ProfileProduction
)
// DetectEnvironment determines the current environment profile
func DetectEnvironment() EnvironmentProfile {
// CI detection
if os.Getenv("CI") != "" || os.Getenv("GITHUB_ACTIONS") != "" || os.Getenv("GITLAB_CI") != "" {
return ProfileCI
}
// Container detection
if _, err := os.Stat("/.dockerenv"); err == nil {
return ProfileContainer
}
if os.Getenv("KUBERNETES_SERVICE_HOST") != "" {
return ProfileContainer
}
if os.Getenv("CONTAINER") != "" {
return ProfileContainer
}
// Production detection (customizable)
if os.Getenv("FETCH_ML_ENV") == "production" || os.Getenv("ENV") == "production" {
return ProfileProduction
}
// Default to local development
return ProfileLocal
}
// SmartDefaults provides environment-aware default values
type SmartDefaults struct {
Profile EnvironmentProfile
}
// GetSmartDefaults returns defaults for the current environment
func GetSmartDefaults() *SmartDefaults {
return &SmartDefaults{
Profile: DetectEnvironment(),
}
}
// Host returns the appropriate default host
func (s *SmartDefaults) Host() string {
switch s.Profile {
case ProfileContainer, ProfileCI:
return "host.docker.internal" // Docker Desktop/Colima
case ProfileProduction:
return "0.0.0.0"
default: // ProfileLocal
return "localhost"
}
}
// BasePath returns the appropriate default base path
func (s *SmartDefaults) BasePath() string {
switch s.Profile {
case ProfileContainer, ProfileCI:
return "/workspace/ml-experiments"
case ProfileProduction:
return "/var/lib/fetch_ml/experiments"
default: // ProfileLocal
if home, err := os.UserHomeDir(); err == nil {
return filepath.Join(home, "ml-experiments")
}
return "./ml-experiments"
}
}
// DataDir returns the appropriate default data directory
func (s *SmartDefaults) DataDir() string {
switch s.Profile {
case ProfileContainer, ProfileCI:
return "/workspace/data"
case ProfileProduction:
return "/var/lib/fetch_ml/data"
default: // ProfileLocal
if home, err := os.UserHomeDir(); err == nil {
return filepath.Join(home, "ml-data")
}
return "./data"
}
}
// RedisAddr returns the appropriate default Redis address
func (s *SmartDefaults) RedisAddr() string {
switch s.Profile {
case ProfileContainer, ProfileCI:
return "redis:6379" // Service name in containers
case ProfileProduction:
return "redis:6379"
default: // ProfileLocal
return "localhost:6379"
}
}
// SSHKeyPath returns the appropriate default SSH key path
func (s *SmartDefaults) SSHKeyPath() string {
switch s.Profile {
case ProfileContainer, ProfileCI:
return "/workspace/.ssh/id_rsa"
case ProfileProduction:
return "/etc/fetch_ml/ssh/id_rsa"
default: // ProfileLocal
if home, err := os.UserHomeDir(); err == nil {
return filepath.Join(home, ".ssh", "id_rsa")
}
return "~/.ssh/id_rsa"
}
}
// KnownHostsPath returns the appropriate default known_hosts path
func (s *SmartDefaults) KnownHostsPath() string {
switch s.Profile {
case ProfileContainer, ProfileCI:
return "/workspace/.ssh/known_hosts"
case ProfileProduction:
return "/etc/fetch_ml/ssh/known_hosts"
default: // ProfileLocal
if home, err := os.UserHomeDir(); err == nil {
return filepath.Join(home, ".ssh", "known_hosts")
}
return "~/.ssh/known_hosts"
}
}
// LogLevel returns the appropriate default log level
func (s *SmartDefaults) LogLevel() string {
switch s.Profile {
case ProfileCI:
return "debug" // More verbose for CI debugging
case ProfileProduction:
return "info"
default: // ProfileLocal, ProfileContainer
return "info"
}
}
// MaxWorkers returns the appropriate default worker count
func (s *SmartDefaults) MaxWorkers() int {
switch s.Profile {
case ProfileCI:
return 1 // Conservative for CI
case ProfileProduction:
return runtime.NumCPU() // Scale with CPU cores
default: // ProfileLocal, ProfileContainer
return 2 // Reasonable default for local dev
}
}
// PollInterval returns the appropriate default poll interval in seconds
func (s *SmartDefaults) PollInterval() int {
switch s.Profile {
case ProfileCI:
return 1 // Fast polling for quick tests
case ProfileProduction:
return 10 // Conservative for production
default: // ProfileLocal, ProfileContainer
return 5 // Balanced default
}
}
// IsInContainer returns true if running in a container environment
func (s *SmartDefaults) IsInContainer() bool {
return s.Profile == ProfileContainer || s.Profile == ProfileCI
}
// IsProduction returns true if this is a production environment
func (s *SmartDefaults) IsProduction() bool {
return s.Profile == ProfileProduction
}
// IsCI returns true if this is a CI environment
func (s *SmartDefaults) IsCI() bool {
return s.Profile == ProfileCI
}
// ExpandPath expands ~ and environment variables in paths
func (s *SmartDefaults) ExpandPath(path string) string {
if strings.HasPrefix(path, "~/") {
if home, err := os.UserHomeDir(); err == nil {
path = filepath.Join(home, path[2:])
}
}
// Expand environment variables
path = os.ExpandEnv(path)
return path
}
// GetEnvironmentDescription returns a human-readable description
func (s *SmartDefaults) GetEnvironmentDescription() string {
switch s.Profile {
case ProfileLocal:
return "Local Development"
case ProfileContainer:
return "Container Environment"
case ProfileCI:
return "CI/CD Environment"
case ProfileProduction:
return "Production Environment"
default:
return "Unknown Environment"
}
}