- 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
222 lines
5.6 KiB
Go
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"
|
|
}
|
|
}
|