You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							270 lines
						
					
					
						
							7.8 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							270 lines
						
					
					
						
							7.8 KiB
						
					
					
				| package dash | |
| 
 | |
| import ( | |
| 	"encoding/json" | |
| 	"fmt" | |
| 	"os" | |
| 	"path/filepath" | |
| 	"time" | |
| 
 | |
| 	"github.com/seaweedfs/seaweedfs/weed/glog" | |
| ) | |
| 
 | |
| const ( | |
| 	// Configuration file names | |
| 	MaintenanceConfigFile = "maintenance.json" | |
| 	AdminConfigFile       = "admin.json" | |
| 	ConfigDirPermissions  = 0755 | |
| 	ConfigFilePermissions = 0644 | |
| ) | |
| 
 | |
| // ConfigPersistence handles saving and loading configuration files | |
| type ConfigPersistence struct { | |
| 	dataDir string | |
| } | |
| 
 | |
| // NewConfigPersistence creates a new configuration persistence manager | |
| func NewConfigPersistence(dataDir string) *ConfigPersistence { | |
| 	return &ConfigPersistence{ | |
| 		dataDir: dataDir, | |
| 	} | |
| } | |
| 
 | |
| // SaveMaintenanceConfig saves maintenance configuration to JSON file | |
| func (cp *ConfigPersistence) SaveMaintenanceConfig(config *MaintenanceConfig) error { | |
| 	if cp.dataDir == "" { | |
| 		return fmt.Errorf("no data directory specified, cannot save configuration") | |
| 	} | |
| 
 | |
| 	configPath := filepath.Join(cp.dataDir, MaintenanceConfigFile) | |
| 
 | |
| 	// Create directory if it doesn't exist | |
| 	if err := os.MkdirAll(cp.dataDir, ConfigDirPermissions); err != nil { | |
| 		return fmt.Errorf("failed to create config directory: %v", err) | |
| 	} | |
| 
 | |
| 	// Marshal configuration to JSON | |
| 	configData, err := json.MarshalIndent(config, "", "  ") | |
| 	if err != nil { | |
| 		return fmt.Errorf("failed to marshal maintenance config: %v", err) | |
| 	} | |
| 
 | |
| 	// Write to file | |
| 	if err := os.WriteFile(configPath, configData, ConfigFilePermissions); err != nil { | |
| 		return fmt.Errorf("failed to write maintenance config file: %v", err) | |
| 	} | |
| 
 | |
| 	glog.V(1).Infof("Saved maintenance configuration to %s", configPath) | |
| 	return nil | |
| } | |
| 
 | |
| // LoadMaintenanceConfig loads maintenance configuration from JSON file | |
| func (cp *ConfigPersistence) LoadMaintenanceConfig() (*MaintenanceConfig, error) { | |
| 	if cp.dataDir == "" { | |
| 		glog.V(1).Infof("No data directory specified, using default maintenance configuration") | |
| 		return DefaultMaintenanceConfig(), nil | |
| 	} | |
| 
 | |
| 	configPath := filepath.Join(cp.dataDir, MaintenanceConfigFile) | |
| 
 | |
| 	// Check if file exists | |
| 	if _, err := os.Stat(configPath); os.IsNotExist(err) { | |
| 		glog.V(1).Infof("Maintenance config file does not exist, using defaults: %s", configPath) | |
| 		return DefaultMaintenanceConfig(), nil | |
| 	} | |
| 
 | |
| 	// Read file | |
| 	configData, err := os.ReadFile(configPath) | |
| 	if err != nil { | |
| 		return nil, fmt.Errorf("failed to read maintenance config file: %v", err) | |
| 	} | |
| 
 | |
| 	// Unmarshal JSON | |
| 	var config MaintenanceConfig | |
| 	if err := json.Unmarshal(configData, &config); err != nil { | |
| 		return nil, fmt.Errorf("failed to unmarshal maintenance config: %v", err) | |
| 	} | |
| 
 | |
| 	glog.V(1).Infof("Loaded maintenance configuration from %s", configPath) | |
| 	return &config, nil | |
| } | |
| 
 | |
| // SaveAdminConfig saves general admin configuration to JSON file | |
| func (cp *ConfigPersistence) SaveAdminConfig(config map[string]interface{}) error { | |
| 	if cp.dataDir == "" { | |
| 		return fmt.Errorf("no data directory specified, cannot save configuration") | |
| 	} | |
| 
 | |
| 	configPath := filepath.Join(cp.dataDir, AdminConfigFile) | |
| 
 | |
| 	// Create directory if it doesn't exist | |
| 	if err := os.MkdirAll(cp.dataDir, ConfigDirPermissions); err != nil { | |
| 		return fmt.Errorf("failed to create config directory: %v", err) | |
| 	} | |
| 
 | |
| 	// Marshal configuration to JSON | |
| 	configData, err := json.MarshalIndent(config, "", "  ") | |
| 	if err != nil { | |
| 		return fmt.Errorf("failed to marshal admin config: %v", err) | |
| 	} | |
| 
 | |
| 	// Write to file | |
| 	if err := os.WriteFile(configPath, configData, ConfigFilePermissions); err != nil { | |
| 		return fmt.Errorf("failed to write admin config file: %v", err) | |
| 	} | |
| 
 | |
| 	glog.V(1).Infof("Saved admin configuration to %s", configPath) | |
| 	return nil | |
| } | |
| 
 | |
| // LoadAdminConfig loads general admin configuration from JSON file | |
| func (cp *ConfigPersistence) LoadAdminConfig() (map[string]interface{}, error) { | |
| 	if cp.dataDir == "" { | |
| 		glog.V(1).Infof("No data directory specified, using default admin configuration") | |
| 		return make(map[string]interface{}), nil | |
| 	} | |
| 
 | |
| 	configPath := filepath.Join(cp.dataDir, AdminConfigFile) | |
| 
 | |
| 	// Check if file exists | |
| 	if _, err := os.Stat(configPath); os.IsNotExist(err) { | |
| 		glog.V(1).Infof("Admin config file does not exist, using defaults: %s", configPath) | |
| 		return make(map[string]interface{}), nil | |
| 	} | |
| 
 | |
| 	// Read file | |
| 	configData, err := os.ReadFile(configPath) | |
| 	if err != nil { | |
| 		return nil, fmt.Errorf("failed to read admin config file: %v", err) | |
| 	} | |
| 
 | |
| 	// Unmarshal JSON | |
| 	var config map[string]interface{} | |
| 	if err := json.Unmarshal(configData, &config); err != nil { | |
| 		return nil, fmt.Errorf("failed to unmarshal admin config: %v", err) | |
| 	} | |
| 
 | |
| 	glog.V(1).Infof("Loaded admin configuration from %s", configPath) | |
| 	return config, nil | |
| } | |
| 
 | |
| // GetConfigPath returns the path to a configuration file | |
| func (cp *ConfigPersistence) GetConfigPath(filename string) string { | |
| 	if cp.dataDir == "" { | |
| 		return "" | |
| 	} | |
| 	return filepath.Join(cp.dataDir, filename) | |
| } | |
| 
 | |
| // ListConfigFiles returns all configuration files in the data directory | |
| func (cp *ConfigPersistence) ListConfigFiles() ([]string, error) { | |
| 	if cp.dataDir == "" { | |
| 		return nil, fmt.Errorf("no data directory specified") | |
| 	} | |
| 
 | |
| 	files, err := os.ReadDir(cp.dataDir) | |
| 	if err != nil { | |
| 		return nil, fmt.Errorf("failed to read config directory: %v", err) | |
| 	} | |
| 
 | |
| 	var configFiles []string | |
| 	for _, file := range files { | |
| 		if !file.IsDir() && filepath.Ext(file.Name()) == ".json" { | |
| 			configFiles = append(configFiles, file.Name()) | |
| 		} | |
| 	} | |
| 
 | |
| 	return configFiles, nil | |
| } | |
| 
 | |
| // BackupConfig creates a backup of a configuration file | |
| func (cp *ConfigPersistence) BackupConfig(filename string) error { | |
| 	if cp.dataDir == "" { | |
| 		return fmt.Errorf("no data directory specified") | |
| 	} | |
| 
 | |
| 	configPath := filepath.Join(cp.dataDir, filename) | |
| 	if _, err := os.Stat(configPath); os.IsNotExist(err) { | |
| 		return fmt.Errorf("config file does not exist: %s", filename) | |
| 	} | |
| 
 | |
| 	// Create backup filename with timestamp | |
| 	timestamp := time.Now().Format("2006-01-02_15-04-05") | |
| 	backupName := fmt.Sprintf("%s.backup_%s", filename, timestamp) | |
| 	backupPath := filepath.Join(cp.dataDir, backupName) | |
| 
 | |
| 	// Copy file | |
| 	configData, err := os.ReadFile(configPath) | |
| 	if err != nil { | |
| 		return fmt.Errorf("failed to read config file: %v", err) | |
| 	} | |
| 
 | |
| 	if err := os.WriteFile(backupPath, configData, ConfigFilePermissions); err != nil { | |
| 		return fmt.Errorf("failed to create backup: %v", err) | |
| 	} | |
| 
 | |
| 	glog.V(1).Infof("Created backup of %s as %s", filename, backupName) | |
| 	return nil | |
| } | |
| 
 | |
| // RestoreConfig restores a configuration file from a backup | |
| func (cp *ConfigPersistence) RestoreConfig(filename, backupName string) error { | |
| 	if cp.dataDir == "" { | |
| 		return fmt.Errorf("no data directory specified") | |
| 	} | |
| 
 | |
| 	backupPath := filepath.Join(cp.dataDir, backupName) | |
| 	if _, err := os.Stat(backupPath); os.IsNotExist(err) { | |
| 		return fmt.Errorf("backup file does not exist: %s", backupName) | |
| 	} | |
| 
 | |
| 	// Read backup file | |
| 	backupData, err := os.ReadFile(backupPath) | |
| 	if err != nil { | |
| 		return fmt.Errorf("failed to read backup file: %v", err) | |
| 	} | |
| 
 | |
| 	// Write to config file | |
| 	configPath := filepath.Join(cp.dataDir, filename) | |
| 	if err := os.WriteFile(configPath, backupData, ConfigFilePermissions); err != nil { | |
| 		return fmt.Errorf("failed to restore config: %v", err) | |
| 	} | |
| 
 | |
| 	glog.V(1).Infof("Restored %s from backup %s", filename, backupName) | |
| 	return nil | |
| } | |
| 
 | |
| // GetDataDir returns the data directory path | |
| func (cp *ConfigPersistence) GetDataDir() string { | |
| 	return cp.dataDir | |
| } | |
| 
 | |
| // IsConfigured returns true if a data directory is configured | |
| func (cp *ConfigPersistence) IsConfigured() bool { | |
| 	return cp.dataDir != "" | |
| } | |
| 
 | |
| // GetConfigInfo returns information about the configuration storage | |
| func (cp *ConfigPersistence) GetConfigInfo() map[string]interface{} { | |
| 	info := map[string]interface{}{ | |
| 		"data_dir_configured": cp.IsConfigured(), | |
| 		"data_dir":            cp.dataDir, | |
| 	} | |
| 
 | |
| 	if cp.IsConfigured() { | |
| 		// Check if data directory exists | |
| 		if _, err := os.Stat(cp.dataDir); err == nil { | |
| 			info["data_dir_exists"] = true | |
| 
 | |
| 			// List config files | |
| 			configFiles, err := cp.ListConfigFiles() | |
| 			if err == nil { | |
| 				info["config_files"] = configFiles | |
| 			} | |
| 		} else { | |
| 			info["data_dir_exists"] = false | |
| 		} | |
| 	} | |
| 
 | |
| 	return info | |
| }
 |