| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  |  * MinIO Cloud Storage, (C) 2018 MinIO, Inc. | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"path" | 
					
						
							|  |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2018-10-09 06:47:13 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/minio/minio/cmd/logger" | 
					
						
							|  |  |  | 	"github.com/minio/minio/pkg/quick" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	minioConfigPrefix = "config" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | 	// MinIO configuration file.
 | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	minioConfigFile = "config.json" | 
					
						
							| 
									
										
										
										
											2018-09-06 23:03:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | 	// MinIO backup file
 | 
					
						
							| 
									
										
										
										
											2018-09-06 23:03:18 +08:00
										 |  |  | 	minioConfigBackupFile = minioConfigFile + ".backup" | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 23:03:18 +08:00
										 |  |  | func saveServerConfig(ctx context.Context, objAPI ObjectLayer, config *serverConfig) error { | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	if err := quick.CheckData(config); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 23:03:18 +08:00
										 |  |  | 	data, err := json.MarshalIndent(config, "", "\t") | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	configFile := path.Join(minioConfigPrefix, minioConfigFile) | 
					
						
							|  |  |  | 	if globalEtcdClient != nil { | 
					
						
							| 
									
										
										
										
											2019-01-19 01:36:45 +08:00
										 |  |  | 		return saveConfigEtcd(ctx, globalEtcdClient, configFile, data) | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 23:03:18 +08:00
										 |  |  | 	// Create a backup of the current config
 | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 	oldData, err := readConfig(ctx, objAPI, configFile) | 
					
						
							| 
									
										
										
										
											2018-09-06 23:03:18 +08:00
										 |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		backupConfigFile := path.Join(minioConfigPrefix, minioConfigBackupFile) | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 		if err = saveConfig(ctx, objAPI, backupConfigFile, oldData); err != nil { | 
					
						
							| 
									
										
										
										
											2018-09-06 23:03:18 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if err != errConfigNotFound { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Save the new config in the std config path
 | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 	return saveConfig(ctx, objAPI, configFile, data) | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func readServerConfig(ctx context.Context, objAPI ObjectLayer) (*serverConfig, error) { | 
					
						
							|  |  |  | 	var configData []byte | 
					
						
							|  |  |  | 	var err error | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	configFile := path.Join(minioConfigPrefix, minioConfigFile) | 
					
						
							|  |  |  | 	if globalEtcdClient != nil { | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 		configData, err = readConfigEtcd(ctx, globalEtcdClient, configFile) | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 		configData, err = readConfig(ctx, objAPI, configFile) | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if runtime.GOOS == "windows" { | 
					
						
							|  |  |  | 		configData = bytes.Replace(configData, []byte("\r\n"), []byte("\n"), -1) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err = quick.CheckDuplicateKeys(string(configData)); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var config = &serverConfig{} | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 	if err = json.Unmarshal(configData, config); err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 	if err = quick.CheckData(config); err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return config, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ConfigSys - config system.
 | 
					
						
							|  |  |  | type ConfigSys struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Load - load config.json.
 | 
					
						
							|  |  |  | func (sys *ConfigSys) Load(objAPI ObjectLayer) error { | 
					
						
							|  |  |  | 	return sys.Init(objAPI) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Init - initializes config system from config.json.
 | 
					
						
							|  |  |  | func (sys *ConfigSys) Init(objAPI ObjectLayer) error { | 
					
						
							|  |  |  | 	if objAPI == nil { | 
					
						
							|  |  |  | 		return errInvalidArgument | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-16 13:09:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	doneCh := make(chan struct{}) | 
					
						
							|  |  |  | 	defer close(doneCh) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initializing configuration needs a retry mechanism for
 | 
					
						
							|  |  |  | 	// the following reasons:
 | 
					
						
							|  |  |  | 	//  - Read quorum is lost just after the initialization
 | 
					
						
							|  |  |  | 	//    of the object layer.
 | 
					
						
							|  |  |  | 	//  - Write quorum not met when upgrading configuration
 | 
					
						
							|  |  |  | 	//    version is needed.
 | 
					
						
							| 
									
										
										
										
											2019-02-13 20:59:36 +08:00
										 |  |  | 	for range newRetryTimerSimple(doneCh) { | 
					
						
							|  |  |  | 		if err := initConfig(objAPI); err != nil { | 
					
						
							|  |  |  | 			if strings.Contains(err.Error(), InsufficientReadQuorum{}.Error()) || | 
					
						
							|  |  |  | 				strings.Contains(err.Error(), InsufficientWriteQuorum{}.Error()) { | 
					
						
							|  |  |  | 				logger.Info("Waiting for configuration to be initialized..") | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2018-09-16 13:09:51 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-02-13 20:59:36 +08:00
										 |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2018-09-16 13:09:51 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-02-13 20:59:36 +08:00
										 |  |  | 		break | 
					
						
							| 
									
										
										
										
											2018-09-16 13:09:51 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-13 20:59:36 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewConfigSys - creates new config system object.
 | 
					
						
							|  |  |  | func NewConfigSys() *ConfigSys { | 
					
						
							|  |  |  | 	return &ConfigSys{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Initialize and load config from remote etcd or local config directory
 | 
					
						
							| 
									
										
										
										
											2018-08-20 04:57:18 +08:00
										 |  |  | func initConfig(objAPI ObjectLayer) error { | 
					
						
							|  |  |  | 	if objAPI == nil { | 
					
						
							|  |  |  | 		return errServerNotInitialized | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-29 05:31:35 +08:00
										 |  |  | 	configFile := path.Join(minioConfigPrefix, minioConfigFile) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	if globalEtcdClient != nil { | 
					
						
							| 
									
										
										
										
											2019-01-19 01:36:45 +08:00
										 |  |  | 		if err := checkConfigEtcd(context.Background(), globalEtcdClient, getConfigFile()); err != nil { | 
					
						
							| 
									
										
										
										
											2019-01-24 03:10:59 +08:00
										 |  |  | 			if err == errConfigNotFound { | 
					
						
							|  |  |  | 				// Migrates all configs at old location.
 | 
					
						
							|  |  |  | 				if err = migrateConfig(); err != nil { | 
					
						
							|  |  |  | 					return err | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// Migrates etcd ${HOME}/.minio/config.json to '/config/config.json'
 | 
					
						
							|  |  |  | 				if err = migrateConfigToMinioSys(objAPI); err != nil { | 
					
						
							|  |  |  | 					return err | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-01-29 05:31:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Watch config for changes and reloads them.
 | 
					
						
							|  |  |  | 		go watchConfigEtcd(objAPI, configFile, loadConfig) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		if isFile(getConfigFile()) { | 
					
						
							| 
									
										
										
										
											2018-08-20 04:57:18 +08:00
										 |  |  | 			if err := migrateConfig(); err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-09-11 07:15:47 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		// Migrates ${HOME}/.minio/config.json or config.json.deprecated
 | 
					
						
							|  |  |  | 		// to '<export_path>/.minio.sys/config/config.json'
 | 
					
						
							| 
									
										
										
										
											2018-09-11 09:24:57 +08:00
										 |  |  | 		// ignore if the file doesn't exist.
 | 
					
						
							| 
									
										
										
										
											2019-01-24 03:10:59 +08:00
										 |  |  | 		if err := migrateConfigToMinioSys(objAPI); err != nil { | 
					
						
							| 
									
										
										
										
											2018-09-11 07:15:47 +08:00
										 |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-20 04:57:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-29 05:31:35 +08:00
										 |  |  | 		// Migrates backend '<export_path>/.minio.sys/config/config.json' to latest version.
 | 
					
						
							|  |  |  | 		if err := migrateMinioSysConfig(objAPI); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-20 04:57:18 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-18 09:51:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-20 04:57:18 +08:00
										 |  |  | 	return loadConfig(objAPI) | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | } |