diff options
Diffstat (limited to 'weed/kms/config_loader.go')
| -rw-r--r-- | weed/kms/config_loader.go | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/weed/kms/config_loader.go b/weed/kms/config_loader.go new file mode 100644 index 000000000..3778c0f59 --- /dev/null +++ b/weed/kms/config_loader.go @@ -0,0 +1,426 @@ +package kms + +import ( + "context" + "fmt" + "time" + + "github.com/seaweedfs/seaweedfs/weed/glog" +) + +// ViperConfig interface extends Configuration with additional methods needed for KMS configuration +type ViperConfig interface { + GetString(key string) string + GetBool(key string) bool + GetInt(key string) int + GetStringSlice(key string) []string + SetDefault(key string, value interface{}) + GetStringMap(key string) map[string]interface{} + IsSet(key string) bool +} + +// ConfigLoader handles loading KMS configurations from filer.toml +type ConfigLoader struct { + viper ViperConfig + manager *KMSManager +} + +// NewConfigLoader creates a new KMS configuration loader +func NewConfigLoader(v ViperConfig) *ConfigLoader { + return &ConfigLoader{ + viper: v, + manager: GetKMSManager(), + } +} + +// LoadConfigurations loads all KMS provider configurations from filer.toml +func (loader *ConfigLoader) LoadConfigurations() error { + // Check if KMS section exists + if !loader.viper.IsSet("kms") { + glog.V(1).Infof("No KMS configuration found in filer.toml") + return nil + } + + // Get the KMS configuration section + kmsConfig := loader.viper.GetStringMap("kms") + + // Load global KMS settings + if err := loader.loadGlobalKMSSettings(kmsConfig); err != nil { + return fmt.Errorf("failed to load global KMS settings: %w", err) + } + + // Load KMS providers + if providersConfig, exists := kmsConfig["providers"]; exists { + if providers, ok := providersConfig.(map[string]interface{}); ok { + if err := loader.loadKMSProviders(providers); err != nil { + return fmt.Errorf("failed to load KMS providers: %w", err) + } + } + } + + // Set default provider after all providers are loaded + if err := loader.setDefaultProvider(); err != nil { + return fmt.Errorf("failed to set default KMS provider: %w", err) + } + + // Initialize global KMS provider for backwards compatibility + if err := loader.initializeGlobalKMSProvider(); err != nil { + glog.Warningf("Failed to initialize global KMS provider: %v", err) + } + + // Load bucket-specific KMS configurations + if bucketsConfig, exists := kmsConfig["buckets"]; exists { + if buckets, ok := bucketsConfig.(map[string]interface{}); ok { + if err := loader.loadBucketKMSConfigurations(buckets); err != nil { + return fmt.Errorf("failed to load bucket KMS configurations: %w", err) + } + } + } + + glog.V(1).Infof("KMS configuration loaded successfully") + return nil +} + +// loadGlobalKMSSettings loads global KMS settings +func (loader *ConfigLoader) loadGlobalKMSSettings(kmsConfig map[string]interface{}) error { + // Set default KMS provider if specified + if defaultProvider, exists := kmsConfig["default_provider"]; exists { + if providerName, ok := defaultProvider.(string); ok { + // We'll set this after providers are loaded + glog.V(2).Infof("Default KMS provider will be set to: %s", providerName) + } + } + + return nil +} + +// loadKMSProviders loads individual KMS provider configurations +func (loader *ConfigLoader) loadKMSProviders(providers map[string]interface{}) error { + for providerName, providerConfigInterface := range providers { + providerConfig, ok := providerConfigInterface.(map[string]interface{}) + if !ok { + glog.Warningf("Invalid configuration for KMS provider %s", providerName) + continue + } + + if err := loader.loadSingleKMSProvider(providerName, providerConfig); err != nil { + glog.Errorf("Failed to load KMS provider %s: %v", providerName, err) + continue + } + + glog.V(1).Infof("Loaded KMS provider: %s", providerName) + } + + return nil +} + +// loadSingleKMSProvider loads a single KMS provider configuration +func (loader *ConfigLoader) loadSingleKMSProvider(providerName string, config map[string]interface{}) error { + // Get provider type + providerType, exists := config["type"] + if !exists { + return fmt.Errorf("provider type not specified for %s", providerName) + } + + providerTypeStr, ok := providerType.(string) + if !ok { + return fmt.Errorf("invalid provider type for %s", providerName) + } + + // Get provider-specific configuration + providerConfig := make(map[string]interface{}) + for key, value := range config { + if key != "type" { + providerConfig[key] = value + } + } + + // Set default cache settings if not specified + if _, exists := providerConfig["cache_enabled"]; !exists { + providerConfig["cache_enabled"] = true + } + + if _, exists := providerConfig["cache_ttl"]; !exists { + providerConfig["cache_ttl"] = "1h" + } + + if _, exists := providerConfig["max_cache_size"]; !exists { + providerConfig["max_cache_size"] = 1000 + } + + // Parse cache TTL + cacheTTL := time.Hour // default + if ttlStr, exists := providerConfig["cache_ttl"]; exists { + if ttlStrValue, ok := ttlStr.(string); ok { + if parsed, err := time.ParseDuration(ttlStrValue); err == nil { + cacheTTL = parsed + } + } + } + + // Create KMS configuration + kmsConfig := &KMSConfig{ + Provider: providerTypeStr, + Config: providerConfig, + CacheEnabled: getBoolFromConfig(providerConfig, "cache_enabled", true), + CacheTTL: cacheTTL, + MaxCacheSize: getIntFromConfig(providerConfig, "max_cache_size", 1000), + } + + // Add the provider to the KMS manager + if err := loader.manager.AddKMSProvider(providerName, kmsConfig); err != nil { + return err + } + + // Test the provider with a health check + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + health := loader.manager.GetKMSHealth(ctx) + if providerHealth, exists := health[providerName]; exists && providerHealth != nil { + glog.Warningf("KMS provider %s health check failed: %v", providerName, providerHealth) + } + + return nil +} + +// loadBucketKMSConfigurations loads bucket-specific KMS configurations +func (loader *ConfigLoader) loadBucketKMSConfigurations(buckets map[string]interface{}) error { + for bucketName, bucketConfigInterface := range buckets { + bucketConfig, ok := bucketConfigInterface.(map[string]interface{}) + if !ok { + glog.Warningf("Invalid KMS configuration for bucket %s", bucketName) + continue + } + + // Get provider for this bucket + if provider, exists := bucketConfig["provider"]; exists { + if providerName, ok := provider.(string); ok { + if err := loader.manager.SetBucketKMSProvider(bucketName, providerName); err != nil { + glog.Errorf("Failed to set KMS provider for bucket %s: %v", bucketName, err) + continue + } + glog.V(2).Infof("Set KMS provider for bucket %s to %s", bucketName, providerName) + } + } + } + + return nil +} + +// setDefaultProvider sets the default KMS provider after all providers are loaded +func (loader *ConfigLoader) setDefaultProvider() error { + kmsConfig := loader.viper.GetStringMap("kms") + if defaultProvider, exists := kmsConfig["default_provider"]; exists { + if providerName, ok := defaultProvider.(string); ok { + if err := loader.manager.SetDefaultKMSProvider(providerName); err != nil { + return fmt.Errorf("failed to set default KMS provider: %w", err) + } + glog.V(1).Infof("Set default KMS provider to: %s", providerName) + } + } + return nil +} + +// initializeGlobalKMSProvider initializes the global KMS provider for backwards compatibility +func (loader *ConfigLoader) initializeGlobalKMSProvider() error { + // Get the default provider from the manager + defaultProviderName := "" + kmsConfig := loader.viper.GetStringMap("kms") + if defaultProvider, exists := kmsConfig["default_provider"]; exists { + if providerName, ok := defaultProvider.(string); ok { + defaultProviderName = providerName + } + } + + if defaultProviderName == "" { + // If no default provider, try to use the first available provider + providers := loader.manager.ListKMSProviders() + if len(providers) > 0 { + defaultProviderName = providers[0] + } + } + + if defaultProviderName == "" { + glog.V(2).Infof("No KMS providers configured, skipping global KMS initialization") + return nil + } + + // Get the provider from the manager + provider, err := loader.manager.GetKMSProviderByName(defaultProviderName) + if err != nil { + return fmt.Errorf("failed to get KMS provider %s: %w", defaultProviderName, err) + } + + // Set as global KMS provider + SetGlobalKMSProvider(provider) + glog.V(1).Infof("Initialized global KMS provider: %s", defaultProviderName) + + return nil +} + +// ValidateConfiguration validates the KMS configuration +func (loader *ConfigLoader) ValidateConfiguration() error { + providers := loader.manager.ListKMSProviders() + if len(providers) == 0 { + glog.V(1).Infof("No KMS providers configured") + return nil + } + + // Test connectivity to all providers + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + health := loader.manager.GetKMSHealth(ctx) + hasHealthyProvider := false + + for providerName, err := range health { + if err != nil { + glog.Warningf("KMS provider %s is unhealthy: %v", providerName, err) + } else { + hasHealthyProvider = true + glog.V(2).Infof("KMS provider %s is healthy", providerName) + } + } + + if !hasHealthyProvider { + glog.Warningf("No healthy KMS providers found") + } + + return nil +} + +// LoadKMSFromFilerToml is a convenience function to load KMS configuration from filer.toml +func LoadKMSFromFilerToml(v ViperConfig) error { + loader := NewConfigLoader(v) + if err := loader.LoadConfigurations(); err != nil { + return err + } + return loader.ValidateConfiguration() +} + +// LoadKMSFromConfig loads KMS configuration directly from parsed JSON data +func LoadKMSFromConfig(kmsConfig interface{}) error { + kmsMap, ok := kmsConfig.(map[string]interface{}) + if !ok { + return fmt.Errorf("invalid KMS configuration format") + } + + // Create a direct config adapter that doesn't use Viper + // Wrap the KMS config under a "kms" key as expected by LoadConfigurations + wrappedConfig := map[string]interface{}{ + "kms": kmsMap, + } + adapter := &directConfigAdapter{config: wrappedConfig} + loader := NewConfigLoader(adapter) + + if err := loader.LoadConfigurations(); err != nil { + return err + } + + return loader.ValidateConfiguration() +} + +// directConfigAdapter implements ViperConfig interface for direct map access +type directConfigAdapter struct { + config map[string]interface{} +} + +func (d *directConfigAdapter) GetStringMap(key string) map[string]interface{} { + if val, exists := d.config[key]; exists { + if mapVal, ok := val.(map[string]interface{}); ok { + return mapVal + } + } + return make(map[string]interface{}) +} + +func (d *directConfigAdapter) GetString(key string) string { + if val, exists := d.config[key]; exists { + if strVal, ok := val.(string); ok { + return strVal + } + } + return "" +} + +func (d *directConfigAdapter) GetBool(key string) bool { + if val, exists := d.config[key]; exists { + if boolVal, ok := val.(bool); ok { + return boolVal + } + } + return false +} + +func (d *directConfigAdapter) GetInt(key string) int { + if val, exists := d.config[key]; exists { + switch v := val.(type) { + case int: + return v + case float64: + return int(v) + } + } + return 0 +} + +func (d *directConfigAdapter) GetStringSlice(key string) []string { + if val, exists := d.config[key]; exists { + if sliceVal, ok := val.([]interface{}); ok { + result := make([]string, len(sliceVal)) + for i, item := range sliceVal { + if strItem, ok := item.(string); ok { + result[i] = strItem + } + } + return result + } + if strSlice, ok := val.([]string); ok { + return strSlice + } + } + return []string{} +} + +func (d *directConfigAdapter) SetDefault(key string, value interface{}) { + // For direct config adapter, we don't need to set defaults + // as the configuration is already parsed +} + +func (d *directConfigAdapter) IsSet(key string) bool { + _, exists := d.config[key] + return exists +} + +// Helper functions + +func getBoolFromConfig(config map[string]interface{}, key string, defaultValue bool) bool { + if value, exists := config[key]; exists { + if boolValue, ok := value.(bool); ok { + return boolValue + } + } + return defaultValue +} + +func getIntFromConfig(config map[string]interface{}, key string, defaultValue int) int { + if value, exists := config[key]; exists { + if intValue, ok := value.(int); ok { + return intValue + } + if floatValue, ok := value.(float64); ok { + return int(floatValue) + } + } + return defaultValue +} + +func getStringFromConfig(config map[string]interface{}, key string, defaultValue string) string { + if value, exists := config[key]; exists { + if stringValue, ok := value.(string); ok { + return stringValue + } + } + return defaultValue +} |
