726 lines
28 KiB
Go
726 lines
28 KiB
Go
package leader
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
"chorus/pkg/config"
|
|
)
|
|
|
|
// SLURPLeaderConfig represents comprehensive configuration for SLURP-enabled leader election
|
|
type SLURPLeaderConfig struct {
|
|
// Core configuration
|
|
Core *CoreConfig `yaml:"core" json:"core"`
|
|
|
|
// Election configuration
|
|
Election *ElectionConfig `yaml:"election" json:"election"`
|
|
|
|
// Context management configuration
|
|
ContextManagement *ContextManagementConfig `yaml:"context_management" json:"context_management"`
|
|
|
|
// Failover configuration
|
|
Failover *FailoverConfig `yaml:"failover" json:"failover"`
|
|
|
|
// Health monitoring configuration
|
|
Health *HealthConfig `yaml:"health" json:"health"`
|
|
|
|
// Metrics and logging configuration
|
|
Observability *ObservabilityConfig `yaml:"observability" json:"observability"`
|
|
|
|
// Performance configuration
|
|
Performance *PerformanceConfig `yaml:"performance" json:"performance"`
|
|
|
|
// Security configuration
|
|
Security *SecurityConfig `yaml:"security" json:"security"`
|
|
}
|
|
|
|
// CoreConfig represents core SLURP leader configuration
|
|
type CoreConfig struct {
|
|
// Basic settings
|
|
NodeID string `yaml:"node_id" json:"node_id"`
|
|
ClusterID string `yaml:"cluster_id" json:"cluster_id"`
|
|
DataDirectory string `yaml:"data_directory" json:"data_directory"`
|
|
|
|
// Capabilities
|
|
Capabilities []string `yaml:"capabilities" json:"capabilities"`
|
|
ProjectManagerEnabled bool `yaml:"project_manager_enabled" json:"project_manager_enabled"`
|
|
ContextCurationEnabled bool `yaml:"context_curation_enabled" json:"context_curation_enabled"`
|
|
|
|
// Networking
|
|
ListenAddress string `yaml:"listen_address" json:"listen_address"`
|
|
AdvertiseAddress string `yaml:"advertise_address" json:"advertise_address"`
|
|
|
|
// Timeouts
|
|
StartupTimeout time.Duration `yaml:"startup_timeout" json:"startup_timeout"`
|
|
ShutdownTimeout time.Duration `yaml:"shutdown_timeout" json:"shutdown_timeout"`
|
|
|
|
// Debug settings
|
|
DebugMode bool `yaml:"debug_mode" json:"debug_mode"`
|
|
VerboseLogging bool `yaml:"verbose_logging" json:"verbose_logging"`
|
|
}
|
|
|
|
// ElectionConfig represents leader election configuration
|
|
type ElectionConfig struct {
|
|
// Election settings
|
|
ElectionTimeout time.Duration `yaml:"election_timeout" json:"election_timeout"`
|
|
HeartbeatInterval time.Duration `yaml:"heartbeat_interval" json:"heartbeat_interval"`
|
|
HeartbeatTimeout time.Duration `yaml:"heartbeat_timeout" json:"heartbeat_timeout"`
|
|
DiscoveryTimeout time.Duration `yaml:"discovery_timeout" json:"discovery_timeout"`
|
|
DiscoveryBackoff time.Duration `yaml:"discovery_backoff" json:"discovery_backoff"`
|
|
|
|
// Scoring configuration
|
|
LeadershipScoring *LeadershipScoringConfig `yaml:"leadership_scoring" json:"leadership_scoring"`
|
|
|
|
// Context leadership
|
|
ContextLeadershipWeight float64 `yaml:"context_leadership_weight" json:"context_leadership_weight"`
|
|
RequireContextCapability bool `yaml:"require_context_capability" json:"require_context_capability"`
|
|
AutoStartGeneration bool `yaml:"auto_start_generation" json:"auto_start_generation"`
|
|
GenerationStartDelay time.Duration `yaml:"generation_start_delay" json:"generation_start_delay"`
|
|
GenerationStopTimeout time.Duration `yaml:"generation_stop_timeout" json:"generation_stop_timeout"`
|
|
|
|
// Quorum settings
|
|
MinQuorumSize int `yaml:"min_quorum_size" json:"min_quorum_size"`
|
|
RequireQuorum bool `yaml:"require_quorum" json:"require_quorum"`
|
|
|
|
// Split brain prevention
|
|
SplitBrainDetection bool `yaml:"split_brain_detection" json:"split_brain_detection"`
|
|
SplitBrainTimeout time.Duration `yaml:"split_brain_timeout" json:"split_brain_timeout"`
|
|
}
|
|
|
|
// LeadershipScoringConfig represents leadership scoring configuration
|
|
type LeadershipScoringConfig struct {
|
|
UptimeWeight float64 `yaml:"uptime_weight" json:"uptime_weight"`
|
|
CapabilityWeight float64 `yaml:"capability_weight" json:"capability_weight"`
|
|
ResourceWeight float64 `yaml:"resource_weight" json:"resource_weight"`
|
|
NetworkWeight float64 `yaml:"network_weight" json:"network_weight"`
|
|
ExperienceWeight float64 `yaml:"experience_weight" json:"experience_weight"`
|
|
ContextCapabilityBonus float64 `yaml:"context_capability_bonus" json:"context_capability_bonus"`
|
|
ProjectManagerBonus float64 `yaml:"project_manager_bonus" json:"project_manager_bonus"`
|
|
}
|
|
|
|
// ContextManagementConfig represents context management configuration
|
|
type ContextManagementConfig struct {
|
|
// Queue configuration
|
|
QueueSize int `yaml:"queue_size" json:"queue_size"`
|
|
MaxConcurrentJobs int `yaml:"max_concurrent_jobs" json:"max_concurrent_jobs"`
|
|
MaxCompletedJobs int `yaml:"max_completed_jobs" json:"max_completed_jobs"`
|
|
JobTimeout time.Duration `yaml:"job_timeout" json:"job_timeout"`
|
|
QueueDrainTimeout time.Duration `yaml:"queue_drain_timeout" json:"queue_drain_timeout"`
|
|
|
|
// Processing configuration
|
|
ProcessingTimeout time.Duration `yaml:"processing_timeout" json:"processing_timeout"`
|
|
RetryAttempts int `yaml:"retry_attempts" json:"retry_attempts"`
|
|
RetryBackoff time.Duration `yaml:"retry_backoff" json:"retry_backoff"`
|
|
|
|
// Context generation configuration
|
|
MaxHierarchyDepth int `yaml:"max_hierarchy_depth" json:"max_hierarchy_depth"`
|
|
ContextCacheTTL time.Duration `yaml:"context_cache_ttl" json:"context_cache_ttl"`
|
|
GenerationConcurrency int `yaml:"generation_concurrency" json:"generation_concurrency"`
|
|
ConfidenceThreshold float64 `yaml:"confidence_threshold" json:"confidence_threshold"`
|
|
|
|
// RAG configuration
|
|
RAGEnabled bool `yaml:"rag_enabled" json:"rag_enabled"`
|
|
RAGEndpoint string `yaml:"rag_endpoint" json:"rag_endpoint"`
|
|
RAGTimeout time.Duration `yaml:"rag_timeout" json:"rag_timeout"`
|
|
RAGMaxRetries int `yaml:"rag_max_retries" json:"rag_max_retries"`
|
|
|
|
// Priority handling
|
|
PriorityQueuing bool `yaml:"priority_queuing" json:"priority_queuing"`
|
|
PriorityWeights map[string]float64 `yaml:"priority_weights" json:"priority_weights"`
|
|
|
|
// Batching configuration
|
|
BatchingEnabled bool `yaml:"batching_enabled" json:"batching_enabled"`
|
|
BatchSize int `yaml:"batch_size" json:"batch_size"`
|
|
BatchTimeout time.Duration `yaml:"batch_timeout" json:"batch_timeout"`
|
|
}
|
|
|
|
// HealthConfig represents health monitoring configuration
|
|
type HealthConfig struct {
|
|
// Health check intervals
|
|
HealthCheckInterval time.Duration `yaml:"health_check_interval" json:"health_check_interval"`
|
|
ClusterHealthInterval time.Duration `yaml:"cluster_health_interval" json:"cluster_health_interval"`
|
|
NodeHealthInterval time.Duration `yaml:"node_health_interval" json:"node_health_interval"`
|
|
|
|
// Health thresholds
|
|
HealthyThreshold float64 `yaml:"healthy_threshold" json:"healthy_threshold"`
|
|
DegradedThreshold float64 `yaml:"degraded_threshold" json:"degraded_threshold"`
|
|
UnhealthyThreshold float64 `yaml:"unhealthy_threshold" json:"unhealthy_threshold"`
|
|
CriticalThreshold float64 `yaml:"critical_threshold" json:"critical_threshold"`
|
|
|
|
// Performance thresholds
|
|
MaxResponseTime time.Duration `yaml:"max_response_time" json:"max_response_time"`
|
|
MaxQueueUtilization float64 `yaml:"max_queue_utilization" json:"max_queue_utilization"`
|
|
MaxProcessingLatency time.Duration `yaml:"max_processing_latency" json:"max_processing_latency"`
|
|
MaxMemoryUsage float64 `yaml:"max_memory_usage" json:"max_memory_usage"`
|
|
MaxCPUUsage float64 `yaml:"max_cpu_usage" json:"max_cpu_usage"`
|
|
|
|
// Health actions
|
|
AutoRecovery bool `yaml:"auto_recovery" json:"auto_recovery"`
|
|
FailoverOnCritical bool `yaml:"failover_on_critical" json:"failover_on_critical"`
|
|
AlertOnDegraded bool `yaml:"alert_on_degraded" json:"alert_on_degraded"`
|
|
|
|
// Circuit breaker
|
|
CircuitBreakerEnabled bool `yaml:"circuit_breaker_enabled" json:"circuit_breaker_enabled"`
|
|
CircuitBreakerThreshold int `yaml:"circuit_breaker_threshold" json:"circuit_breaker_threshold"`
|
|
CircuitBreakerTimeout time.Duration `yaml:"circuit_breaker_timeout" json:"circuit_breaker_timeout"`
|
|
}
|
|
|
|
// ObservabilityConfig represents monitoring and logging configuration
|
|
type ObservabilityConfig struct {
|
|
// Logging configuration
|
|
LogLevel string `yaml:"log_level" json:"log_level"`
|
|
LogFormat string `yaml:"log_format" json:"log_format"` // "console", "json"
|
|
LogOutput []string `yaml:"log_output" json:"log_output"` // "console", "file", "syslog"
|
|
LogFile string `yaml:"log_file" json:"log_file"`
|
|
LogRotation *LogRotationConfig `yaml:"log_rotation" json:"log_rotation"`
|
|
|
|
// Metrics configuration
|
|
MetricsEnabled bool `yaml:"metrics_enabled" json:"metrics_enabled"`
|
|
MetricsInterval time.Duration `yaml:"metrics_interval" json:"metrics_interval"`
|
|
MetricsRetention time.Duration `yaml:"metrics_retention" json:"metrics_retention"`
|
|
MetricsExport *MetricsExportConfig `yaml:"metrics_export" json:"metrics_export"`
|
|
|
|
// Tracing configuration
|
|
TracingEnabled bool `yaml:"tracing_enabled" json:"tracing_enabled"`
|
|
TracingSampleRate float64 `yaml:"tracing_sample_rate" json:"tracing_sample_rate"`
|
|
TracingEndpoint string `yaml:"tracing_endpoint" json:"tracing_endpoint"`
|
|
|
|
// Event logging
|
|
EventLogging bool `yaml:"event_logging" json:"event_logging"`
|
|
EventBuffer int `yaml:"event_buffer" json:"event_buffer"`
|
|
EventRetention time.Duration `yaml:"event_retention" json:"event_retention"`
|
|
}
|
|
|
|
// LogRotationConfig represents log rotation configuration
|
|
type LogRotationConfig struct {
|
|
MaxSize string `yaml:"max_size" json:"max_size"` // "100MB"
|
|
MaxAge string `yaml:"max_age" json:"max_age"` // "30d"
|
|
MaxBackups int `yaml:"max_backups" json:"max_backups"`
|
|
Compress bool `yaml:"compress" json:"compress"`
|
|
}
|
|
|
|
// MetricsExportConfig represents metrics export configuration
|
|
type MetricsExportConfig struct {
|
|
Enabled bool `yaml:"enabled" json:"enabled"`
|
|
Format string `yaml:"format" json:"format"` // "prometheus", "json"
|
|
Endpoint string `yaml:"endpoint" json:"endpoint"`
|
|
Interval time.Duration `yaml:"interval" json:"interval"`
|
|
Labels map[string]string `yaml:"labels" json:"labels"`
|
|
}
|
|
|
|
// PerformanceConfig represents performance tuning configuration
|
|
type PerformanceConfig struct {
|
|
// Resource limits
|
|
MaxMemoryUsage string `yaml:"max_memory_usage" json:"max_memory_usage"` // "1GB"
|
|
MaxCPUUsage float64 `yaml:"max_cpu_usage" json:"max_cpu_usage"` // 0.8 = 80%
|
|
MaxFileDescriptors int `yaml:"max_file_descriptors" json:"max_file_descriptors"`
|
|
|
|
// Concurrency settings
|
|
WorkerPoolSize int `yaml:"worker_pool_size" json:"worker_pool_size"`
|
|
IOWorkerPoolSize int `yaml:"io_worker_pool_size" json:"io_worker_pool_size"`
|
|
NetworkWorkerPoolSize int `yaml:"network_worker_pool_size" json:"network_worker_pool_size"`
|
|
|
|
// Buffer sizes
|
|
NetworkBufferSize int `yaml:"network_buffer_size" json:"network_buffer_size"`
|
|
IOBufferSize int `yaml:"io_buffer_size" json:"io_buffer_size"`
|
|
ChannelBufferSize int `yaml:"channel_buffer_size" json:"channel_buffer_size"`
|
|
|
|
// Garbage collection tuning
|
|
GCTargetPercentage int `yaml:"gc_target_percentage" json:"gc_target_percentage"`
|
|
GCMemoryLimit string `yaml:"gc_memory_limit" json:"gc_memory_limit"`
|
|
|
|
// Cache configuration
|
|
CacheEnabled bool `yaml:"cache_enabled" json:"cache_enabled"`
|
|
CacheSize int `yaml:"cache_size" json:"cache_size"`
|
|
CacheTTL time.Duration `yaml:"cache_ttl" json:"cache_ttl"`
|
|
CacheEvictionPolicy string `yaml:"cache_eviction_policy" json:"cache_eviction_policy"` // "lru", "lfu", "ttl"
|
|
}
|
|
|
|
// SecurityConfig represents security configuration
|
|
type SecurityConfig struct {
|
|
// TLS configuration
|
|
TLSEnabled bool `yaml:"tls_enabled" json:"tls_enabled"`
|
|
TLSCertFile string `yaml:"tls_cert_file" json:"tls_cert_file"`
|
|
TLSKeyFile string `yaml:"tls_key_file" json:"tls_key_file"`
|
|
TLSCAFile string `yaml:"tls_ca_file" json:"tls_ca_file"`
|
|
TLSSkipVerify bool `yaml:"tls_skip_verify" json:"tls_skip_verify"`
|
|
|
|
// Authentication
|
|
AuthEnabled bool `yaml:"auth_enabled" json:"auth_enabled"`
|
|
AuthMethod string `yaml:"auth_method" json:"auth_method"` // "token", "cert", "jwt"
|
|
AuthTokenFile string `yaml:"auth_token_file" json:"auth_token_file"`
|
|
AuthJWTSecret string `yaml:"auth_jwt_secret" json:"auth_jwt_secret"`
|
|
|
|
// Role-based access control
|
|
RBACEnabled bool `yaml:"rbac_enabled" json:"rbac_enabled"`
|
|
RolesConfigFile string `yaml:"roles_config_file" json:"roles_config_file"`
|
|
DefaultRole string `yaml:"default_role" json:"default_role"`
|
|
|
|
// Encryption
|
|
EncryptionEnabled bool `yaml:"encryption_enabled" json:"encryption_enabled"`
|
|
EncryptionAlgorithm string `yaml:"encryption_algorithm" json:"encryption_algorithm"`
|
|
EncryptionKeyFile string `yaml:"encryption_key_file" json:"encryption_key_file"`
|
|
|
|
// Rate limiting
|
|
RateLimitingEnabled bool `yaml:"rate_limiting_enabled" json:"rate_limiting_enabled"`
|
|
RateLimitRPS int `yaml:"rate_limit_rps" json:"rate_limit_rps"`
|
|
RateLimitBurst int `yaml:"rate_limit_burst" json:"rate_limit_burst"`
|
|
|
|
// Security policies
|
|
AllowedNetworks []string `yaml:"allowed_networks" json:"allowed_networks"`
|
|
BlockedNetworks []string `yaml:"blocked_networks" json:"blocked_networks"`
|
|
RequireEncryption bool `yaml:"require_encryption" json:"require_encryption"`
|
|
AuditLogging bool `yaml:"audit_logging" json:"audit_logging"`
|
|
}
|
|
|
|
// DefaultSLURPLeaderConfig returns default configuration for SLURP leader
|
|
func DefaultSLURPLeaderConfig() *SLURPLeaderConfig {
|
|
return &SLURPLeaderConfig{
|
|
Core: &CoreConfig{
|
|
NodeID: "", // Will be auto-generated
|
|
ClusterID: "CHORUS-cluster",
|
|
DataDirectory: "./data",
|
|
Capabilities: []string{"admin_election", "context_curation", "project_manager"},
|
|
ProjectManagerEnabled: true,
|
|
ContextCurationEnabled: true,
|
|
ListenAddress: "0.0.0.0:8080",
|
|
AdvertiseAddress: "", // Will be auto-detected
|
|
StartupTimeout: 30 * time.Second,
|
|
ShutdownTimeout: 15 * time.Second,
|
|
DebugMode: false,
|
|
VerboseLogging: false,
|
|
},
|
|
|
|
Election: &ElectionConfig{
|
|
ElectionTimeout: 10 * time.Second,
|
|
HeartbeatInterval: 2 * time.Second,
|
|
HeartbeatTimeout: 6 * time.Second,
|
|
DiscoveryTimeout: 5 * time.Second,
|
|
DiscoveryBackoff: 2 * time.Second,
|
|
|
|
LeadershipScoring: &LeadershipScoringConfig{
|
|
UptimeWeight: 0.2,
|
|
CapabilityWeight: 0.3,
|
|
ResourceWeight: 0.2,
|
|
NetworkWeight: 0.1,
|
|
ExperienceWeight: 0.2,
|
|
ContextCapabilityBonus: 0.1,
|
|
ProjectManagerBonus: 0.15,
|
|
},
|
|
|
|
ContextLeadershipWeight: 0.3,
|
|
RequireContextCapability: true,
|
|
AutoStartGeneration: true,
|
|
GenerationStartDelay: 5 * time.Second,
|
|
GenerationStopTimeout: 30 * time.Second,
|
|
|
|
MinQuorumSize: 1,
|
|
RequireQuorum: false,
|
|
SplitBrainDetection: true,
|
|
SplitBrainTimeout: 30 * time.Second,
|
|
},
|
|
|
|
ContextManagement: &ContextManagementConfig{
|
|
QueueSize: 10000,
|
|
MaxConcurrentJobs: 10,
|
|
MaxCompletedJobs: 1000,
|
|
JobTimeout: 10 * time.Minute,
|
|
QueueDrainTimeout: 60 * time.Second,
|
|
|
|
ProcessingTimeout: 5 * time.Minute,
|
|
RetryAttempts: 3,
|
|
RetryBackoff: 5 * time.Second,
|
|
|
|
MaxHierarchyDepth: 10,
|
|
ContextCacheTTL: 1 * time.Hour,
|
|
GenerationConcurrency: 5,
|
|
ConfidenceThreshold: 0.7,
|
|
|
|
RAGEnabled: true,
|
|
RAGEndpoint: "http://localhost:8001",
|
|
RAGTimeout: 30 * time.Second,
|
|
RAGMaxRetries: 3,
|
|
|
|
PriorityQueuing: true,
|
|
PriorityWeights: map[string]float64{
|
|
"urgent": 5.0,
|
|
"critical": 4.0,
|
|
"high": 3.0,
|
|
"normal": 2.0,
|
|
"low": 1.0,
|
|
},
|
|
|
|
BatchingEnabled: true,
|
|
BatchSize: 10,
|
|
BatchTimeout: 5 * time.Second,
|
|
},
|
|
|
|
Failover: DefaultFailoverConfig(),
|
|
|
|
Health: &HealthConfig{
|
|
HealthCheckInterval: 30 * time.Second,
|
|
ClusterHealthInterval: 60 * time.Second,
|
|
NodeHealthInterval: 15 * time.Second,
|
|
|
|
HealthyThreshold: 0.8,
|
|
DegradedThreshold: 0.6,
|
|
UnhealthyThreshold: 0.4,
|
|
CriticalThreshold: 0.2,
|
|
|
|
MaxResponseTime: 10 * time.Second,
|
|
MaxQueueUtilization: 0.9,
|
|
MaxProcessingLatency: 5 * time.Minute,
|
|
MaxMemoryUsage: 0.8,
|
|
MaxCPUUsage: 0.8,
|
|
|
|
AutoRecovery: true,
|
|
FailoverOnCritical: true,
|
|
AlertOnDegraded: true,
|
|
|
|
CircuitBreakerEnabled: true,
|
|
CircuitBreakerThreshold: 5,
|
|
CircuitBreakerTimeout: 60 * time.Second,
|
|
},
|
|
|
|
Observability: &ObservabilityConfig{
|
|
LogLevel: "info",
|
|
LogFormat: "console",
|
|
LogOutput: []string{"console"},
|
|
LogFile: "./logs/slurp-leader.log",
|
|
LogRotation: &LogRotationConfig{
|
|
MaxSize: "100MB",
|
|
MaxAge: "30d",
|
|
MaxBackups: 10,
|
|
Compress: true,
|
|
},
|
|
|
|
MetricsEnabled: true,
|
|
MetricsInterval: 30 * time.Second,
|
|
MetricsRetention: 24 * time.Hour,
|
|
MetricsExport: &MetricsExportConfig{
|
|
Enabled: true,
|
|
Format: "prometheus",
|
|
Endpoint: "/metrics",
|
|
Interval: 15 * time.Second,
|
|
Labels: map[string]string{
|
|
"service": "slurp-leader",
|
|
"version": "1.0.0",
|
|
},
|
|
},
|
|
|
|
TracingEnabled: false,
|
|
TracingSampleRate: 0.1,
|
|
TracingEndpoint: "",
|
|
|
|
EventLogging: true,
|
|
EventBuffer: 1000,
|
|
EventRetention: 7 * 24 * time.Hour,
|
|
},
|
|
|
|
Performance: &PerformanceConfig{
|
|
MaxMemoryUsage: "2GB",
|
|
MaxCPUUsage: 0.8,
|
|
MaxFileDescriptors: 65536,
|
|
|
|
WorkerPoolSize: 10,
|
|
IOWorkerPoolSize: 5,
|
|
NetworkWorkerPoolSize: 5,
|
|
|
|
NetworkBufferSize: 65536,
|
|
IOBufferSize: 32768,
|
|
ChannelBufferSize: 1000,
|
|
|
|
GCTargetPercentage: 100,
|
|
GCMemoryLimit: "2GB",
|
|
|
|
CacheEnabled: true,
|
|
CacheSize: 10000,
|
|
CacheTTL: 1 * time.Hour,
|
|
CacheEvictionPolicy: "lru",
|
|
},
|
|
|
|
Security: &SecurityConfig{
|
|
TLSEnabled: false,
|
|
TLSCertFile: "",
|
|
TLSKeyFile: "",
|
|
TLSCAFile: "",
|
|
TLSSkipVerify: false,
|
|
|
|
AuthEnabled: false,
|
|
AuthMethod: "token",
|
|
AuthTokenFile: "",
|
|
AuthJWTSecret: "",
|
|
|
|
RBACEnabled: false,
|
|
RolesConfigFile: "",
|
|
DefaultRole: "guest",
|
|
|
|
EncryptionEnabled: false,
|
|
EncryptionAlgorithm: "AES256",
|
|
EncryptionKeyFile: "",
|
|
|
|
RateLimitingEnabled: false,
|
|
RateLimitRPS: 100,
|
|
RateLimitBurst: 200,
|
|
|
|
AllowedNetworks: []string{},
|
|
BlockedNetworks: []string{},
|
|
RequireEncryption: false,
|
|
AuditLogging: false,
|
|
},
|
|
}
|
|
}
|
|
|
|
// LoadSLURPLeaderConfig loads SLURP leader configuration from file or environment
|
|
func LoadSLURPLeaderConfig(configPath string) (*SLURPLeaderConfig, error) {
|
|
// Start with defaults
|
|
cfg := DefaultSLURPLeaderConfig()
|
|
|
|
// TODO: Load from file if configPath is provided
|
|
|
|
// Override with environment variables
|
|
if err := overrideWithEnvironment(cfg); err != nil {
|
|
return nil, fmt.Errorf("failed to apply environment overrides: %w", err)
|
|
}
|
|
|
|
// Validate configuration
|
|
if err := cfg.Validate(); err != nil {
|
|
return nil, fmt.Errorf("configuration validation failed: %w", err)
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
// Validate validates the configuration for consistency and completeness
|
|
func (cfg *SLURPLeaderConfig) Validate() error {
|
|
if cfg.Core == nil {
|
|
return fmt.Errorf("core configuration is required")
|
|
}
|
|
|
|
if cfg.Election == nil {
|
|
return fmt.Errorf("election configuration is required")
|
|
}
|
|
|
|
if cfg.ContextManagement == nil {
|
|
return fmt.Errorf("context management configuration is required")
|
|
}
|
|
|
|
// Validate core configuration
|
|
if cfg.Core.ClusterID == "" {
|
|
return fmt.Errorf("cluster ID is required")
|
|
}
|
|
|
|
if cfg.Core.DataDirectory == "" {
|
|
return fmt.Errorf("data directory is required")
|
|
}
|
|
|
|
// Validate election configuration
|
|
if cfg.Election.ElectionTimeout <= 0 {
|
|
return fmt.Errorf("election timeout must be positive")
|
|
}
|
|
|
|
if cfg.Election.HeartbeatInterval <= 0 {
|
|
return fmt.Errorf("heartbeat interval must be positive")
|
|
}
|
|
|
|
if cfg.Election.HeartbeatTimeout <= cfg.Election.HeartbeatInterval {
|
|
return fmt.Errorf("heartbeat timeout must be greater than heartbeat interval")
|
|
}
|
|
|
|
// Validate context management configuration
|
|
if cfg.ContextManagement.QueueSize <= 0 {
|
|
return fmt.Errorf("queue size must be positive")
|
|
}
|
|
|
|
if cfg.ContextManagement.MaxConcurrentJobs <= 0 {
|
|
return fmt.Errorf("max concurrent jobs must be positive")
|
|
}
|
|
|
|
// Validate scoring weights sum to reasonable values
|
|
scoring := cfg.Election.LeadershipScoring
|
|
totalWeight := scoring.UptimeWeight + scoring.CapabilityWeight + scoring.ResourceWeight + scoring.NetworkWeight + scoring.ExperienceWeight
|
|
if totalWeight < 0.9 || totalWeight > 1.1 {
|
|
return fmt.Errorf("leadership scoring weights should sum to approximately 1.0, got: %.2f", totalWeight)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ApplyEnvironmentOverrides applies environment variable overrides to configuration
|
|
func (cfg *SLURPLeaderConfig) ApplyEnvironmentOverrides() {
|
|
// TODO: Implement environment variable overrides
|
|
// This would look for environment variables like:
|
|
// SLURP_CORE_NODE_ID
|
|
// SLURP_ELECTION_TIMEOUT
|
|
// SLURP_CONTEXT_QUEUE_SIZE
|
|
// etc.
|
|
}
|
|
|
|
// GetEffectiveConfig returns the effective configuration after applying all overrides
|
|
func (cfg *SLURPLeaderConfig) GetEffectiveConfig() *SLURPLeaderConfig {
|
|
// Make a deep copy
|
|
effective := *cfg
|
|
|
|
// Apply any runtime adjustments
|
|
effective.ApplyEnvironmentOverrides()
|
|
|
|
// Auto-generate node ID if not set
|
|
if effective.Core.NodeID == "" {
|
|
effective.Core.NodeID = fmt.Sprintf("slurp-leader-%d", time.Now().Unix())
|
|
}
|
|
|
|
// Auto-detect advertise address if not set
|
|
if effective.Core.AdvertiseAddress == "" {
|
|
effective.Core.AdvertiseAddress = effective.Core.ListenAddress
|
|
}
|
|
|
|
return &effective
|
|
}
|
|
|
|
// ToBaseCHORUSConfig converts SLURP leader config to base CHORUS config format
|
|
func (cfg *SLURPLeaderConfig) ToBaseCHORUSConfig() *config.Config {
|
|
// TODO: Convert to base CHORUS config structure
|
|
// This would map SLURP-specific configuration to the existing
|
|
// CHORUS configuration structure for compatibility
|
|
|
|
chorusConfig := &config.Config{
|
|
// Map core settings
|
|
// Map agent settings
|
|
// Map security settings
|
|
// etc.
|
|
}
|
|
|
|
return chorusConfig
|
|
}
|
|
|
|
// overrideWithEnvironment applies environment variable overrides to configuration
|
|
func overrideWithEnvironment(cfg *SLURPLeaderConfig) error {
|
|
// Core configuration overrides
|
|
if val := os.Getenv("CHORUS_NODE_ID"); val != "" {
|
|
cfg.Core.NodeID = val
|
|
}
|
|
if val := os.Getenv("CHORUS_CLUSTER_ID"); val != "" {
|
|
cfg.Core.ClusterID = val
|
|
}
|
|
if val := os.Getenv("CHORUS_DATA_DIRECTORY"); val != "" {
|
|
cfg.Core.DataDirectory = val
|
|
}
|
|
if val := os.Getenv("CHORUS_LISTEN_ADDRESS"); val != "" {
|
|
cfg.Core.ListenAddress = val
|
|
}
|
|
if val := os.Getenv("CHORUS_ADVERTISE_ADDRESS"); val != "" {
|
|
cfg.Core.AdvertiseAddress = val
|
|
}
|
|
if val := os.Getenv("CHORUS_DEBUG_MODE"); val != "" {
|
|
if debug, err := strconv.ParseBool(val); err == nil {
|
|
cfg.Core.DebugMode = debug
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_VERBOSE_LOGGING"); val != "" {
|
|
if verbose, err := strconv.ParseBool(val); err == nil {
|
|
cfg.Core.VerboseLogging = verbose
|
|
}
|
|
}
|
|
|
|
// Capabilities override
|
|
if val := os.Getenv("CHORUS_CAPABILITIES"); val != "" {
|
|
cfg.Core.Capabilities = strings.Split(val, ",")
|
|
}
|
|
if val := os.Getenv("CHORUS_PROJECT_MANAGER_ENABLED"); val != "" {
|
|
if enabled, err := strconv.ParseBool(val); err == nil {
|
|
cfg.Core.ProjectManagerEnabled = enabled
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_CONTEXT_CURATION_ENABLED"); val != "" {
|
|
if enabled, err := strconv.ParseBool(val); err == nil {
|
|
cfg.Core.ContextCurationEnabled = enabled
|
|
}
|
|
}
|
|
|
|
// Election configuration overrides
|
|
if val := os.Getenv("CHORUS_ELECTION_TIMEOUT"); val != "" {
|
|
if duration, err := time.ParseDuration(val); err == nil {
|
|
cfg.Election.ElectionTimeout = duration
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_HEARTBEAT_INTERVAL"); val != "" {
|
|
if duration, err := time.ParseDuration(val); err == nil {
|
|
cfg.Election.HeartbeatInterval = duration
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_HEARTBEAT_TIMEOUT"); val != "" {
|
|
if duration, err := time.ParseDuration(val); err == nil {
|
|
cfg.Election.HeartbeatTimeout = duration
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_MIN_QUORUM_SIZE"); val != "" {
|
|
if size, err := strconv.Atoi(val); err == nil {
|
|
cfg.Election.MinQuorumSize = size
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_REQUIRE_QUORUM"); val != "" {
|
|
if require, err := strconv.ParseBool(val); err == nil {
|
|
cfg.Election.RequireQuorum = require
|
|
}
|
|
}
|
|
|
|
// Context management configuration overrides
|
|
if val := os.Getenv("CHORUS_MAX_CONCURRENT_GENERATION"); val != "" {
|
|
if max, err := strconv.Atoi(val); err == nil {
|
|
cfg.ContextManagement.MaxConcurrentGeneration = max
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_GENERATION_TIMEOUT"); val != "" {
|
|
if duration, err := time.ParseDuration(val); err == nil {
|
|
cfg.ContextManagement.GenerationTimeout = duration
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_CONTEXT_CACHE_SIZE"); val != "" {
|
|
if size, err := strconv.Atoi(val); err == nil {
|
|
cfg.ContextManagement.ContextCacheSize = size
|
|
}
|
|
}
|
|
|
|
// Health monitoring overrides
|
|
if val := os.Getenv("CHORUS_HEALTH_CHECK_INTERVAL"); val != "" {
|
|
if duration, err := time.ParseDuration(val); err == nil {
|
|
cfg.Health.HealthCheckInterval = duration
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_HEALTH_CHECK_TIMEOUT"); val != "" {
|
|
if duration, err := time.ParseDuration(val); err == nil {
|
|
cfg.Health.HealthCheckTimeout = duration
|
|
}
|
|
}
|
|
|
|
// Performance overrides
|
|
if val := os.Getenv("CHORUS_WORKER_POOL_SIZE"); val != "" {
|
|
if size, err := strconv.Atoi(val); err == nil {
|
|
cfg.Performance.WorkerPoolSize = size
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_QUEUE_BUFFER_SIZE"); val != "" {
|
|
if size, err := strconv.Atoi(val); err == nil {
|
|
cfg.Performance.QueueBufferSize = size
|
|
}
|
|
}
|
|
|
|
// Observability overrides
|
|
if val := os.Getenv("CHORUS_METRICS_ENABLED"); val != "" {
|
|
if enabled, err := strconv.ParseBool(val); err == nil {
|
|
cfg.Observability.MetricsEnabled = enabled
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_METRICS_PORT"); val != "" {
|
|
if port, err := strconv.Atoi(val); err == nil {
|
|
cfg.Observability.MetricsPort = port
|
|
}
|
|
}
|
|
if val := os.Getenv("CHORUS_LOG_LEVEL"); val != "" {
|
|
cfg.Observability.LogLevel = val
|
|
}
|
|
|
|
return nil
|
|
} |