| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  |  * MinIO Cloud Storage, (C) 2017, 2018 MinIO, Inc. | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +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 ( | 
					
						
							| 
									
										
										
										
											2018-10-30 02:14:12 +08:00
										 |  |  | 	"crypto/tls" | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2018-02-03 10:18:52 +08:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2018-03-30 05:38:26 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-13 05:12:40 +08:00
										 |  |  | 	etcd "github.com/coreos/etcd/clientv3" | 
					
						
							| 
									
										
										
										
											2018-09-21 05:56:32 +08:00
										 |  |  | 	dns2 "github.com/miekg/dns" | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | 	"github.com/minio/cli" | 
					
						
							| 
									
										
										
										
											2019-05-30 07:35:12 +08:00
										 |  |  | 	"github.com/minio/minio-go/v6/pkg/set" | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	"github.com/minio/minio/cmd/logger" | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | 	"github.com/minio/minio/cmd/logger/target/http" | 
					
						
							| 
									
										
										
										
											2017-11-01 02:54:32 +08:00
										 |  |  | 	"github.com/minio/minio/pkg/auth" | 
					
						
							| 
									
										
										
										
											2018-02-03 10:18:52 +08:00
										 |  |  | 	"github.com/minio/minio/pkg/dns" | 
					
						
							| 
									
										
										
										
											2018-11-02 12:41:11 +08:00
										 |  |  | 	xnet "github.com/minio/minio/pkg/net" | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-26 17:41:16 +08:00
										 |  |  | func verifyObjectLayerFeatures(name string, objAPI ObjectLayer) { | 
					
						
							|  |  |  | 	if (globalAutoEncryption || GlobalKMS != nil) && !objAPI.IsEncryptionSupported() { | 
					
						
							|  |  |  | 		logger.Fatal(errInvalidArgument, | 
					
						
							|  |  |  | 			"Encryption support is requested but '%s' does not support encryption", name) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if strings.HasPrefix(name, "gateway") { | 
					
						
							|  |  |  | 		if GlobalGatewaySSE.IsSet() && GlobalKMS == nil { | 
					
						
							|  |  |  | 			uiErr := uiErrInvalidGWSSEEnvValue(nil).Msg("MINIO_GATEWAY_SSE set but KMS is not configured") | 
					
						
							|  |  |  | 			logger.Fatal(uiErr, "Unable to start gateway with SSE") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if globalIsCompressionEnabled && !objAPI.IsCompressionSupported() { | 
					
						
							|  |  |  | 		logger.Fatal(errInvalidArgument, | 
					
						
							|  |  |  | 			"Compression support is requested but '%s' does not support compression", name) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | // Check for updates and print a notification message
 | 
					
						
							|  |  |  | func checkUpdate(mode string) { | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 	// Its OK to ignore any errors during doUpdate() here.
 | 
					
						
							|  |  |  | 	if updateMsg, _, currentReleaseTime, latestReleaseTime, err := getUpdateInfo(2*time.Second, mode); err == nil { | 
					
						
							| 
									
										
										
										
											2019-08-13 12:25:34 +08:00
										 |  |  | 		if updateMsg == "" { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 		if globalInplaceUpdateDisabled { | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 			logger.StartupMessage(updateMsg) | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | 			logger.StartupMessage(prepareUpdateMessage("Run `mc admin update`", latestReleaseTime.Sub(currentReleaseTime))) | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | // Load logger targets based on user's configuration
 | 
					
						
							|  |  |  | func loadLoggers() { | 
					
						
							| 
									
										
										
										
											2019-08-15 02:43:43 +08:00
										 |  |  | 	loggerUserAgent := getUserAgent(getMinioMode()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-03 09:40:08 +08:00
										 |  |  | 	auditEndpoint, ok := os.LookupEnv("MINIO_AUDIT_LOGGER_HTTP_ENDPOINT") | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		// Enable audit HTTP logging through ENV.
 | 
					
						
							| 
									
										
										
										
											2019-08-15 02:43:43 +08:00
										 |  |  | 		logger.AddAuditTarget(http.New(auditEndpoint, loggerUserAgent, NewCustomHTTPTransport())) | 
					
						
							| 
									
										
										
										
											2018-11-03 09:40:08 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	loggerEndpoint, ok := os.LookupEnv("MINIO_LOGGER_HTTP_ENDPOINT") | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		// Enable HTTP logging through ENV.
 | 
					
						
							| 
									
										
										
										
											2019-08-15 02:43:43 +08:00
										 |  |  | 		logger.AddTarget(http.New(loggerEndpoint, loggerUserAgent, NewCustomHTTPTransport())) | 
					
						
							| 
									
										
										
										
											2018-11-03 09:40:08 +08:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		for _, l := range globalServerConfig.Logger.HTTP { | 
					
						
							|  |  |  | 			if l.Enabled { | 
					
						
							|  |  |  | 				// Enable http logging
 | 
					
						
							| 
									
										
										
										
											2019-08-15 02:43:43 +08:00
										 |  |  | 				logger.AddTarget(http.New(l.Endpoint, loggerUserAgent, NewCustomHTTPTransport())) | 
					
						
							| 
									
										
										
										
											2018-11-03 09:40:08 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-13 03:25:59 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 	if globalServerConfig.Logger.Console.Enabled { | 
					
						
							|  |  |  | 		// Enable console logging
 | 
					
						
							| 
									
										
										
										
											2019-09-04 02:10:48 +08:00
										 |  |  | 		logger.AddTarget(globalConsoleSys.Console()) | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-13 03:25:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-17 04:04:32 +08:00
										 |  |  | func newConfigDirFromCtx(ctx *cli.Context, option string, getDefaultDir func() string) (*ConfigDir, bool) { | 
					
						
							| 
									
										
										
										
											2019-01-03 02:05:16 +08:00
										 |  |  | 	var dir string | 
					
						
							| 
									
										
										
										
											2019-01-17 04:04:32 +08:00
										 |  |  | 	var dirSet bool | 
					
						
							| 
									
										
										
										
											2019-01-03 02:05:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case ctx.IsSet(option): | 
					
						
							|  |  |  | 		dir = ctx.String(option) | 
					
						
							| 
									
										
										
										
											2019-01-17 04:04:32 +08:00
										 |  |  | 		dirSet = true | 
					
						
							| 
									
										
										
										
											2019-01-03 02:05:16 +08:00
										 |  |  | 	case ctx.GlobalIsSet(option): | 
					
						
							|  |  |  | 		dir = ctx.GlobalString(option) | 
					
						
							| 
									
										
										
										
											2019-01-17 04:04:32 +08:00
										 |  |  | 		dirSet = true | 
					
						
							| 
									
										
										
										
											2019-01-03 02:05:16 +08:00
										 |  |  | 		// cli package does not expose parent's option option.  Below code is workaround.
 | 
					
						
							|  |  |  | 		if dir == "" || dir == getDefaultDir() { | 
					
						
							| 
									
										
										
										
											2019-01-17 04:04:32 +08:00
										 |  |  | 			dirSet = false // Unset to false since GlobalIsSet() true is a false positive.
 | 
					
						
							| 
									
										
										
										
											2019-01-03 02:05:16 +08:00
										 |  |  | 			if ctx.Parent().GlobalIsSet(option) { | 
					
						
							|  |  |  | 				dir = ctx.Parent().GlobalString(option) | 
					
						
							| 
									
										
										
										
											2019-01-17 04:04:32 +08:00
										 |  |  | 				dirSet = true | 
					
						
							| 
									
										
										
										
											2019-01-03 02:05:16 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		// Neither local nor global option is provided.  In this case, try to use
 | 
					
						
							|  |  |  | 		// default directory.
 | 
					
						
							|  |  |  | 		dir = getDefaultDir() | 
					
						
							|  |  |  | 		if dir == "" { | 
					
						
							|  |  |  | 			logger.FatalIf(errInvalidArgument, "%s option must be provided", option) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if dir == "" { | 
					
						
							|  |  |  | 		logger.FatalIf(errors.New("empty directory"), "%s directory cannot be empty", option) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Disallow relative paths, figure out absolute paths.
 | 
					
						
							|  |  |  | 	dirAbs, err := filepath.Abs(dir) | 
					
						
							|  |  |  | 	logger.FatalIf(err, "Unable to fetch absolute path for %s=%s", option, dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	logger.FatalIf(mkdirAllIgnorePerm(dirAbs), "Unable to create directory specified %s=%s", option, dir) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-17 04:04:32 +08:00
										 |  |  | 	return &ConfigDir{path: dirAbs}, dirSet | 
					
						
							| 
									
										
										
										
											2019-01-03 02:05:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | func handleCommonCmdArgs(ctx *cli.Context) { | 
					
						
							| 
									
										
										
										
											2018-03-01 12:13:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-19 08:08:11 +08:00
										 |  |  | 	// Get "json" flag from command line argument and
 | 
					
						
							| 
									
										
										
										
											2019-02-10 21:49:00 +08:00
										 |  |  | 	// enable json and quite modes if json flag is turned on.
 | 
					
						
							| 
									
										
										
										
											2018-12-19 08:08:11 +08:00
										 |  |  | 	globalCLIContext.JSON = ctx.IsSet("json") || ctx.GlobalIsSet("json") | 
					
						
							|  |  |  | 	if globalCLIContext.JSON { | 
					
						
							|  |  |  | 		logger.EnableJSON() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get quiet flag from command line argument.
 | 
					
						
							|  |  |  | 	globalCLIContext.Quiet = ctx.IsSet("quiet") || ctx.GlobalIsSet("quiet") | 
					
						
							|  |  |  | 	if globalCLIContext.Quiet { | 
					
						
							|  |  |  | 		logger.EnableQuiet() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get anonymous flag from command line argument.
 | 
					
						
							|  |  |  | 	globalCLIContext.Anonymous = ctx.IsSet("anonymous") || ctx.GlobalIsSet("anonymous") | 
					
						
							|  |  |  | 	if globalCLIContext.Anonymous { | 
					
						
							|  |  |  | 		logger.EnableAnonymous() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Fetch address option
 | 
					
						
							|  |  |  | 	globalCLIContext.Addr = ctx.GlobalString("address") | 
					
						
							|  |  |  | 	if globalCLIContext.Addr == "" || globalCLIContext.Addr == ":"+globalMinioDefaultPort { | 
					
						
							|  |  |  | 		globalCLIContext.Addr = ctx.String("address") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-03 02:05:16 +08:00
										 |  |  | 	// Set all config, certs and CAs directories.
 | 
					
						
							| 
									
										
										
										
											2019-01-17 04:04:32 +08:00
										 |  |  | 	var configSet, certsSet bool | 
					
						
							|  |  |  | 	globalConfigDir, configSet = newConfigDirFromCtx(ctx, "config-dir", defaultConfigDir.Get) | 
					
						
							|  |  |  | 	globalCertsDir, certsSet = newConfigDirFromCtx(ctx, "certs-dir", defaultCertsDir.Get) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Remove this code when we deprecate and remove config-dir.
 | 
					
						
							|  |  |  | 	// This code is to make sure we inherit from the config-dir
 | 
					
						
							|  |  |  | 	// option if certs-dir is not provided.
 | 
					
						
							|  |  |  | 	if !certsSet && configSet { | 
					
						
							|  |  |  | 		globalCertsDir = &ConfigDir{path: filepath.Join(globalConfigDir.Get(), certsDir)} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-03 02:05:16 +08:00
										 |  |  | 	globalCertsCADir = &ConfigDir{path: filepath.Join(globalCertsDir.Get(), certsCADir)} | 
					
						
							| 
									
										
										
										
											2018-03-01 12:13:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-03 02:05:16 +08:00
										 |  |  | 	logger.FatalIf(mkdirAllIgnorePerm(globalCertsCADir.Get()), "Unable to create certs CA directory at %s", globalCertsCADir.Get()) | 
					
						
							| 
									
										
										
										
											2019-05-09 09:35:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check "compat" flag from command line argument.
 | 
					
						
							|  |  |  | 	globalCLIContext.StrictS3Compat = ctx.IsSet("compat") || ctx.GlobalIsSet("compat") | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-28 11:36:17 +08:00
										 |  |  | // Parses the given compression exclude list `extensions` or `content-types`.
 | 
					
						
							|  |  |  | func parseCompressIncludes(includes []string) ([]string, error) { | 
					
						
							|  |  |  | 	for _, e := range includes { | 
					
						
							|  |  |  | 		if len(e) == 0 { | 
					
						
							|  |  |  | 			return nil, uiErrInvalidCompressionIncludesValue(nil).Msg("extension/mime-type (%s) cannot be empty", e) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return includes, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | func handleCommonEnvVars() { | 
					
						
							| 
									
										
										
										
											2018-09-28 11:36:17 +08:00
										 |  |  | 	compressEnvDelimiter := "," | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | 	// Start profiler if env is set.
 | 
					
						
							|  |  |  | 	if profiler := os.Getenv("_MINIO_PROFILER"); profiler != "" { | 
					
						
							| 
									
										
										
										
											2018-09-19 07:46:35 +08:00
										 |  |  | 		var err error | 
					
						
							|  |  |  | 		globalProfiler, err = startProfiler(profiler, "") | 
					
						
							|  |  |  | 		logger.FatalIf(err, "Unable to setup a profiler") | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	accessKey := os.Getenv("MINIO_ACCESS_KEY") | 
					
						
							|  |  |  | 	secretKey := os.Getenv("MINIO_SECRET_KEY") | 
					
						
							|  |  |  | 	if accessKey != "" && secretKey != "" { | 
					
						
							| 
									
										
										
										
											2017-11-01 02:54:32 +08:00
										 |  |  | 		cred, err := auth.CreateCredentials(accessKey, secretKey) | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			logger.Fatal(uiErrInvalidCredentials(err), "Unable to validate credentials inherited from the shell environment") | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 		cred.Expiration = timeSentinel | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// credential Envs are set globally.
 | 
					
						
							|  |  |  | 		globalIsEnvCreds = true | 
					
						
							|  |  |  | 		globalActiveCred = cred | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if browser := os.Getenv("MINIO_BROWSER"); browser != "" { | 
					
						
							| 
									
										
										
										
											2018-06-07 09:10:51 +08:00
										 |  |  | 		browserFlag, err := ParseBoolFlag(browser) | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 			logger.Fatal(uiErrInvalidBrowserValue(nil).Msg("Unknown value `%s`", browser), "Invalid MINIO_BROWSER value in environment variable") | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// browser Envs are set globally, this does not represent
 | 
					
						
							|  |  |  | 		// if browser is turned off or on.
 | 
					
						
							|  |  |  | 		globalIsEnvBrowser = true | 
					
						
							|  |  |  | 		globalIsBrowserEnabled = bool(browserFlag) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-10-25 10:04:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-03 10:18:52 +08:00
										 |  |  | 	etcdEndpointsEnv, ok := os.LookupEnv("MINIO_ETCD_ENDPOINTS") | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		etcdEndpoints := strings.Split(etcdEndpointsEnv, ",") | 
					
						
							| 
									
										
										
										
											2018-10-30 02:14:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 12:41:11 +08:00
										 |  |  | 		var etcdSecure bool | 
					
						
							|  |  |  | 		for _, endpoint := range etcdEndpoints { | 
					
						
							|  |  |  | 			u, err := xnet.ParseURL(endpoint) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				logger.FatalIf(err, "Unable to initialize etcd with %s", etcdEndpoints) | 
					
						
							| 
									
										
										
										
											2018-10-30 02:14:12 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-11-02 12:41:11 +08:00
										 |  |  | 			// If one of the endpoint is https, we will use https directly.
 | 
					
						
							|  |  |  | 			etcdSecure = etcdSecure || u.Scheme == "https" | 
					
						
							| 
									
										
										
										
											2018-10-30 02:14:12 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-02 12:41:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-03 10:18:52 +08:00
										 |  |  | 		var err error | 
					
						
							| 
									
										
										
										
											2018-11-02 12:41:11 +08:00
										 |  |  | 		if etcdSecure { | 
					
						
							|  |  |  | 			// This is only to support client side certificate authentication
 | 
					
						
							|  |  |  | 			// https://coreos.com/etcd/docs/latest/op-guide/security.html
 | 
					
						
							|  |  |  | 			etcdClientCertFile, ok1 := os.LookupEnv("MINIO_ETCD_CLIENT_CERT") | 
					
						
							|  |  |  | 			etcdClientCertKey, ok2 := os.LookupEnv("MINIO_ETCD_CLIENT_CERT_KEY") | 
					
						
							|  |  |  | 			var getClientCertificate func(*tls.CertificateRequestInfo) (*tls.Certificate, error) | 
					
						
							|  |  |  | 			if ok1 && ok2 { | 
					
						
							|  |  |  | 				getClientCertificate = func(unused *tls.CertificateRequestInfo) (*tls.Certificate, error) { | 
					
						
							|  |  |  | 					cert, terr := tls.LoadX509KeyPair(etcdClientCertFile, etcdClientCertKey) | 
					
						
							|  |  |  | 					return &cert, terr | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-01-19 01:36:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 12:41:11 +08:00
										 |  |  | 			globalEtcdClient, err = etcd.New(etcd.Config{ | 
					
						
							|  |  |  | 				Endpoints:         etcdEndpoints, | 
					
						
							|  |  |  | 				DialTimeout:       defaultDialTimeout, | 
					
						
							|  |  |  | 				DialKeepAliveTime: defaultDialKeepAlive, | 
					
						
							|  |  |  | 				TLS: &tls.Config{ | 
					
						
							|  |  |  | 					RootCAs:              globalRootCAs, | 
					
						
							|  |  |  | 					GetClientCertificate: getClientCertificate, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			globalEtcdClient, err = etcd.New(etcd.Config{ | 
					
						
							|  |  |  | 				Endpoints:         etcdEndpoints, | 
					
						
							|  |  |  | 				DialTimeout:       defaultDialTimeout, | 
					
						
							|  |  |  | 				DialKeepAliveTime: defaultDialKeepAlive, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-03 10:18:52 +08:00
										 |  |  | 		logger.FatalIf(err, "Unable to initialize etcd with %s", etcdEndpoints) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:18:01 +08:00
										 |  |  | 	v, ok := os.LookupEnv("MINIO_DOMAIN") | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		for _, domainName := range strings.Split(v, ",") { | 
					
						
							|  |  |  | 			if _, ok = dns2.IsDomainName(domainName); !ok { | 
					
						
							|  |  |  | 				logger.Fatal(uiErrInvalidDomainValue(nil).Msg("Unknown value `%s`", domainName), | 
					
						
							|  |  |  | 					"Invalid MINIO_DOMAIN value in environment variable") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			globalDomainNames = append(globalDomainNames, domainName) | 
					
						
							| 
									
										
										
										
											2018-09-21 05:56:32 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-16 09:20:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-12 03:02:30 +08:00
										 |  |  | 	minioEndpointsEnv, ok := os.LookupEnv("MINIO_PUBLIC_IPS") | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		minioEndpoints := strings.Split(minioEndpointsEnv, ",") | 
					
						
							| 
									
										
										
										
											2018-12-23 19:08:21 +08:00
										 |  |  | 		var domainIPs = set.NewStringSet() | 
					
						
							|  |  |  | 		for _, endpoint := range minioEndpoints { | 
					
						
							|  |  |  | 			if net.ParseIP(endpoint) == nil { | 
					
						
							|  |  |  | 				// Checking if the IP is a DNS entry.
 | 
					
						
							|  |  |  | 				addrs, err := net.LookupHost(endpoint) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | 					logger.FatalIf(err, "Unable to initialize MinIO server with [%s] invalid entry found in MINIO_PUBLIC_IPS", endpoint) | 
					
						
							| 
									
										
										
										
											2018-12-23 19:08:21 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				for _, addr := range addrs { | 
					
						
							|  |  |  | 					domainIPs.Add(addr) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2018-05-12 03:02:30 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-12-23 19:08:21 +08:00
										 |  |  | 			domainIPs.Add(endpoint) | 
					
						
							| 
									
										
										
										
											2018-05-12 03:02:30 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-12-23 19:08:21 +08:00
										 |  |  | 		updateDomainIPs(domainIPs) | 
					
						
							| 
									
										
										
										
											2018-12-05 09:35:22 +08:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		// Add found interfaces IP address to global domain IPS,
 | 
					
						
							|  |  |  | 		// loopback addresses will be naturally dropped.
 | 
					
						
							|  |  |  | 		updateDomainIPs(localIP4) | 
					
						
							| 
									
										
										
										
											2018-05-12 03:02:30 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-12-05 09:35:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:18:01 +08:00
										 |  |  | 	if len(globalDomainNames) != 0 && !globalDomainIPs.IsEmpty() && globalEtcdClient != nil { | 
					
						
							| 
									
										
										
										
											2018-02-03 10:18:52 +08:00
										 |  |  | 		var err error | 
					
						
							| 
									
										
										
										
											2019-02-23 11:18:01 +08:00
										 |  |  | 		globalDNSConfig, err = dns.NewCoreDNS(globalDomainNames, globalDomainIPs, globalMinioPort, globalEtcdClient) | 
					
						
							|  |  |  | 		logger.FatalIf(err, "Unable to initialize DNS config for %s.", globalDomainNames) | 
					
						
							| 
									
										
										
										
											2018-02-03 10:18:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-29 05:14:06 +08:00
										 |  |  | 	if drives := os.Getenv("MINIO_CACHE_DRIVES"); drives != "" { | 
					
						
							| 
									
										
										
										
											2018-03-30 05:38:26 +08:00
										 |  |  | 		driveList, err := parseCacheDrives(strings.Split(drives, cacheEnvDelimiter)) | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			logger.Fatal(err, "Unable to parse MINIO_CACHE_DRIVES value (%s)", drives) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-03-29 05:14:06 +08:00
										 |  |  | 		globalCacheDrives = driveList | 
					
						
							|  |  |  | 		globalIsDiskCacheEnabled = true | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-29 05:14:06 +08:00
										 |  |  | 	if excludes := os.Getenv("MINIO_CACHE_EXCLUDE"); excludes != "" { | 
					
						
							| 
									
										
										
										
											2018-03-30 05:38:26 +08:00
										 |  |  | 		excludeList, err := parseCacheExcludes(strings.Split(excludes, cacheEnvDelimiter)) | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-10 06:11:24 +08:00
										 |  |  | 			logger.Fatal(err, "Unable to parse MINIO_CACHE_EXCLUDE value (`%s`)", excludes) | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-03-29 05:14:06 +08:00
										 |  |  | 		globalCacheExcludes = excludeList | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-29 05:14:06 +08:00
										 |  |  | 	if expiryStr := os.Getenv("MINIO_CACHE_EXPIRY"); expiryStr != "" { | 
					
						
							| 
									
										
										
										
											2018-03-30 05:38:26 +08:00
										 |  |  | 		expiry, err := strconv.Atoi(expiryStr) | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			logger.Fatal(uiErrInvalidCacheExpiryValue(err), "Unable to parse MINIO_CACHE_EXPIRY value (`%s`)", expiryStr) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-03-29 05:14:06 +08:00
										 |  |  | 		globalCacheExpiry = expiry | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-30 05:38:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 01:24:12 +08:00
										 |  |  | 	if maxUseStr := os.Getenv("MINIO_CACHE_MAXUSE"); maxUseStr != "" { | 
					
						
							|  |  |  | 		maxUse, err := strconv.Atoi(maxUseStr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			logger.Fatal(uiErrInvalidCacheMaxUse(err), "Unable to parse MINIO_CACHE_MAXUSE value (`%s`)", maxUseStr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// maxUse should be a valid percentage.
 | 
					
						
							|  |  |  | 		if maxUse > 0 && maxUse <= 100 { | 
					
						
							|  |  |  | 			globalCacheMaxUse = maxUse | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-24 01:13:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 	if cacheEncKey := os.Getenv("MINIO_CACHE_ENCRYPTION_MASTER_KEY"); cacheEncKey != "" { | 
					
						
							|  |  |  | 		globalCacheKMSKeyID, globalCacheKMS, err = parseKMSMasterKey(cacheEncKey) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			logger.Fatal(uiErrInvalidCacheEncryptionKey(err), "Invalid cache encryption master key") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 	// In place update is true by default if the MINIO_UPDATE is not set
 | 
					
						
							|  |  |  | 	// or is not set to 'off', if MINIO_UPDATE is set to 'off' then
 | 
					
						
							|  |  |  | 	// in-place update is off.
 | 
					
						
							|  |  |  | 	globalInplaceUpdateDisabled = strings.EqualFold(os.Getenv("MINIO_UPDATE"), "off") | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Validate and store the storage class env variables only for XL/Dist XL setups
 | 
					
						
							|  |  |  | 	if globalIsXL { | 
					
						
							|  |  |  | 		var err error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Check for environment variables and parse into storageClass struct
 | 
					
						
							| 
									
										
										
										
											2017-12-27 12:36:16 +08:00
										 |  |  | 		if ssc := os.Getenv(standardStorageClassEnv); ssc != "" { | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			globalStandardStorageClass, err = parseStorageClass(ssc) | 
					
						
							| 
									
										
										
										
											2018-05-10 06:11:24 +08:00
										 |  |  | 			logger.FatalIf(err, "Invalid value set in environment variable %s", standardStorageClassEnv) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-27 12:36:16 +08:00
										 |  |  | 		if rrsc := os.Getenv(reducedRedundancyStorageClassEnv); rrsc != "" { | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			globalRRStorageClass, err = parseStorageClass(rrsc) | 
					
						
							| 
									
										
										
										
											2018-05-10 06:11:24 +08:00
										 |  |  | 			logger.FatalIf(err, "Invalid value set in environment variable %s", reducedRedundancyStorageClassEnv) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Validation is done after parsing both the storage classes. This is needed because we need one
 | 
					
						
							|  |  |  | 		// storage class value to deduce the correct value of the other storage class.
 | 
					
						
							|  |  |  | 		if globalRRStorageClass.Scheme != "" { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			err = validateParity(globalStandardStorageClass.Parity, globalRRStorageClass.Parity) | 
					
						
							| 
									
										
										
										
											2018-05-10 06:11:24 +08:00
										 |  |  | 			logger.FatalIf(err, "Invalid value set in environment variable %s", reducedRedundancyStorageClassEnv) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			globalIsStorageClass = true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if globalStandardStorageClass.Scheme != "" { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			err = validateParity(globalStandardStorageClass.Parity, globalRRStorageClass.Parity) | 
					
						
							| 
									
										
										
										
											2018-05-10 06:11:24 +08:00
										 |  |  | 			logger.FatalIf(err, "Invalid value set in environment variable %s", standardStorageClassEnv) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			globalIsStorageClass = true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-28 07:44:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Get WORM environment variable.
 | 
					
						
							| 
									
										
										
										
											2018-06-07 09:10:51 +08:00
										 |  |  | 	if worm := os.Getenv("MINIO_WORM"); worm != "" { | 
					
						
							|  |  |  | 		wormFlag, err := ParseBoolFlag(worm) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 			logger.Fatal(uiErrInvalidWormValue(nil).Msg("Unknown value `%s`", worm), "Invalid MINIO_WORM value in environment variable") | 
					
						
							| 
									
										
										
										
											2018-06-07 09:10:51 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// worm Envs are set globally, this does not represent
 | 
					
						
							|  |  |  | 		// if worm is turned off or on.
 | 
					
						
							|  |  |  | 		globalIsEnvWORM = true | 
					
						
							|  |  |  | 		globalWORMEnabled = bool(wormFlag) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-28 11:36:17 +08:00
										 |  |  | 	if compress := os.Getenv("MINIO_COMPRESS"); compress != "" { | 
					
						
							|  |  |  | 		globalIsCompressionEnabled = strings.EqualFold(compress, "true") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	compressExtensions := os.Getenv("MINIO_COMPRESS_EXTENSIONS") | 
					
						
							|  |  |  | 	compressMimeTypes := os.Getenv("MINIO_COMPRESS_MIMETYPES") | 
					
						
							|  |  |  | 	if compressExtensions != "" || compressMimeTypes != "" { | 
					
						
							|  |  |  | 		globalIsEnvCompression = true | 
					
						
							|  |  |  | 		if compressExtensions != "" { | 
					
						
							|  |  |  | 			extensions, err := parseCompressIncludes(strings.Split(compressExtensions, compressEnvDelimiter)) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				logger.Fatal(err, "Invalid MINIO_COMPRESS_EXTENSIONS value (`%s`)", extensions) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			globalCompressExtensions = extensions | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if compressMimeTypes != "" { | 
					
						
							|  |  |  | 			contenttypes, err := parseCompressIncludes(strings.Split(compressMimeTypes, compressEnvDelimiter)) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				logger.Fatal(err, "Invalid MINIO_COMPRESS_MIMETYPES value (`%s`)", contenttypes) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			globalCompressMimeTypes = contenttypes | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-10 10:50:51 +08:00
										 |  |  | } |