| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Minio Cloud Storage, (C) 2017 Minio, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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 ( | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2017-04-12 08:44:26 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2017-04-12 08:44:26 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/gorilla/mux" | 
					
						
							|  |  |  | 	"github.com/minio/cli" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var gatewayTemplate = `NAME: | 
					
						
							|  |  |  |   {{.HelpName}} - {{.Usage}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | USAGE: | 
					
						
							| 
									
										
										
										
											2017-04-15 02:02:43 +08:00
										 |  |  |   {{.HelpName}} {{if .VisibleFlags}}[FLAGS]{{end}} BACKEND [ENDPOINT] | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | {{if .VisibleFlags}} | 
					
						
							|  |  |  | FLAGS: | 
					
						
							|  |  |  |   {{range .VisibleFlags}}{{.}} | 
					
						
							|  |  |  |   {{end}}{{end}} | 
					
						
							| 
									
										
										
										
											2017-04-29 07:42:16 +08:00
										 |  |  | BACKEND: | 
					
						
							|  |  |  |   azure: Microsoft Azure Blob Storage. Default ENDPOINT is https://core.windows.net
 | 
					
						
							| 
									
										
										
										
											2017-05-05 01:38:48 +08:00
										 |  |  |   s3: Amazon Simple Storage Service (S3). Default ENDPOINT is https://s3.amazonaws.com
 | 
					
						
							| 
									
										
										
										
											2017-04-29 07:42:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | ENVIRONMENT VARIABLES: | 
					
						
							|  |  |  |   ACCESS: | 
					
						
							|  |  |  |      MINIO_ACCESS_KEY: Username or access key of your storage backend. | 
					
						
							|  |  |  |      MINIO_SECRET_KEY: Password or secret key of your storage backend. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EXAMPLES: | 
					
						
							|  |  |  |   1. Start minio gateway server for Azure Blob Storage backend. | 
					
						
							| 
									
										
										
										
											2017-04-29 07:42:16 +08:00
										 |  |  |       $ export MINIO_ACCESS_KEY=azureaccountname | 
					
						
							|  |  |  |       $ export MINIO_SECRET_KEY=azureaccountkey | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  |       $ {{.HelpName}} azure | 
					
						
							| 
									
										
										
										
											2017-05-04 08:55:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-05 01:38:48 +08:00
										 |  |  |   2. Start minio gateway server for AWS S3 backend. | 
					
						
							| 
									
										
										
										
											2017-05-04 08:55:30 +08:00
										 |  |  |       $ export MINIO_ACCESS_KEY=accesskey | 
					
						
							|  |  |  |       $ export MINIO_SECRET_KEY=secretkey | 
					
						
							|  |  |  |       $ {{.HelpName}} s3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   3. Start minio gateway server for S3 backend on custom endpoint. | 
					
						
							|  |  |  |       $ export MINIO_ACCESS_KEY=Q3AM3UQ867SPQQA43P2F | 
					
						
							|  |  |  |       $ export MINIO_SECRET_KEY=zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG | 
					
						
							|  |  |  |       $ {{.HelpName}} s3 https://play.minio.io:9000
 | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | ` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var gatewayCmd = cli.Command{ | 
					
						
							|  |  |  | 	Name:               "gateway", | 
					
						
							| 
									
										
										
										
											2017-04-29 07:42:16 +08:00
										 |  |  | 	Usage:              "Start object storage gateway.", | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	Action:             gatewayMain, | 
					
						
							|  |  |  | 	CustomHelpTemplate: gatewayTemplate, | 
					
						
							| 
									
										
										
										
											2017-04-29 07:42:16 +08:00
										 |  |  | 	Flags: append(serverFlags, | 
					
						
							|  |  |  | 		cli.BoolFlag{ | 
					
						
							|  |  |  | 			Name:  "quiet", | 
					
						
							|  |  |  | 			Usage: "Disable startup banner.", | 
					
						
							| 
									
										
										
										
											2017-04-28 02:26:00 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	), | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	HideHelpCommand: true, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Represents the type of the gateway backend.
 | 
					
						
							|  |  |  | type gatewayBackend string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	azureBackend gatewayBackend = "azure" | 
					
						
							| 
									
										
										
										
											2017-04-28 02:26:00 +08:00
										 |  |  | 	s3Backend    gatewayBackend = "s3" | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	// Add more backends here.
 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Returns access and secretkey set from environment variables.
 | 
					
						
							|  |  |  | func mustGetGatewayCredsFromEnv() (accessKey, secretKey string) { | 
					
						
							|  |  |  | 	// Fetch access keys from environment variables.
 | 
					
						
							|  |  |  | 	accessKey = os.Getenv("MINIO_ACCESS_KEY") | 
					
						
							|  |  |  | 	secretKey = os.Getenv("MINIO_SECRET_KEY") | 
					
						
							|  |  |  | 	if accessKey == "" || secretKey == "" { | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 		fatalIf(errors.New("Missing credentials"), "Access and secret keys are mandatory to run Minio gateway server.") | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return accessKey, secretKey | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Initialize gateway layer depending on the backend type.
 | 
					
						
							|  |  |  | // Supported backend types are
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // - Azure Blob Storage.
 | 
					
						
							|  |  |  | // - Add your favorite backend here.
 | 
					
						
							| 
									
										
										
										
											2017-04-28 02:26:00 +08:00
										 |  |  | func newGatewayLayer(backendType, endpoint, accessKey, secretKey string, secure bool) (GatewayLayer, error) { | 
					
						
							|  |  |  | 	switch gatewayBackend(backendType) { | 
					
						
							|  |  |  | 	case azureBackend: | 
					
						
							|  |  |  | 		return newAzureLayer(endpoint, accessKey, secretKey, secure) | 
					
						
							|  |  |  | 	case s3Backend: | 
					
						
							|  |  |  | 		return newS3Gateway(endpoint, accessKey, secretKey, secure) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-28 02:26:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return nil, fmt.Errorf("Unrecognized backend type %s", backendType) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Initialize a new gateway config.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // DO NOT save this config, this is meant to be
 | 
					
						
							|  |  |  | // only used in memory.
 | 
					
						
							|  |  |  | func newGatewayConfig(accessKey, secretKey, region string) error { | 
					
						
							|  |  |  | 	// Initialize server config.
 | 
					
						
							| 
									
										
										
										
											2017-03-31 18:34:26 +08:00
										 |  |  | 	srvCfg := newServerConfigV18() | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// If env is set for a fresh start, save them to config file.
 | 
					
						
							|  |  |  | 	srvCfg.SetCredential(credential{ | 
					
						
							|  |  |  | 		AccessKey: accessKey, | 
					
						
							|  |  |  | 		SecretKey: secretKey, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set custom region.
 | 
					
						
							|  |  |  | 	srvCfg.SetRegion(region) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// hold the mutex lock before a new config is assigned.
 | 
					
						
							|  |  |  | 	// Save the new config globally.
 | 
					
						
							|  |  |  | 	// unlock the mutex.
 | 
					
						
							|  |  |  | 	serverConfigMu.Lock() | 
					
						
							|  |  |  | 	serverConfig = srvCfg | 
					
						
							|  |  |  | 	serverConfigMu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 08:44:26 +08:00
										 |  |  | // Return endpoint.
 | 
					
						
							|  |  |  | func parseGatewayEndpoint(arg string) (endPoint string, secure bool, err error) { | 
					
						
							|  |  |  | 	schemeSpecified := len(strings.Split(arg, "://")) > 1 | 
					
						
							|  |  |  | 	if !schemeSpecified { | 
					
						
							|  |  |  | 		// Default connection will be "secure".
 | 
					
						
							|  |  |  | 		arg = "https://" + arg | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-28 02:26:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 08:44:26 +08:00
										 |  |  | 	u, err := url.Parse(arg) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", false, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch u.Scheme { | 
					
						
							|  |  |  | 	case "http": | 
					
						
							|  |  |  | 		return u.Host, false, nil | 
					
						
							|  |  |  | 	case "https": | 
					
						
							|  |  |  | 		return u.Host, true, nil | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return "", false, fmt.Errorf("Unrecognized scheme %s", u.Scheme) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | // Handler for 'minio gateway'.
 | 
					
						
							|  |  |  | func gatewayMain(ctx *cli.Context) { | 
					
						
							|  |  |  | 	if !ctx.Args().Present() || ctx.Args().First() == "help" { | 
					
						
							|  |  |  | 		cli.ShowCommandHelpAndExit(ctx, "gateway", 1) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Fetch access and secret key from env.
 | 
					
						
							|  |  |  | 	accessKey, secretKey := mustGetGatewayCredsFromEnv() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize new gateway config.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// TODO: add support for custom region when we add
 | 
					
						
							|  |  |  | 	// support for S3 backend storage, currently this can
 | 
					
						
							|  |  |  | 	// default to "us-east-1"
 | 
					
						
							| 
									
										
										
										
											2017-03-31 13:26:24 +08:00
										 |  |  | 	newGatewayConfig(accessKey, secretKey, globalMinioDefaultRegion) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Get quiet flag from command line argument.
 | 
					
						
							|  |  |  | 	quietFlag := ctx.Bool("quiet") || ctx.GlobalBool("quiet") | 
					
						
							| 
									
										
										
										
											2017-03-31 02:21:19 +08:00
										 |  |  | 	if quietFlag { | 
					
						
							|  |  |  | 		log.EnableQuiet() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// First argument is selected backend type.
 | 
					
						
							|  |  |  | 	backendType := ctx.Args().First() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 08:44:26 +08:00
										 |  |  | 	// Second argument is endpoint.	If no endpoint is specified then the
 | 
					
						
							|  |  |  | 	// gateway implementation should use a default setting.
 | 
					
						
							|  |  |  | 	endPoint, secure, err := parseGatewayEndpoint(ctx.Args().Get(1)) | 
					
						
							|  |  |  | 	fatalIf(err, "Unable to parse endpoint") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-31 13:26:24 +08:00
										 |  |  | 	// Create certs path for SSL configuration.
 | 
					
						
							|  |  |  | 	fatalIf(createConfigDir(), "Unable to create configuration directory") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 08:44:26 +08:00
										 |  |  | 	newObject, err := newGatewayLayer(backendType, endPoint, accessKey, secretKey, secure) | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	fatalIf(err, "Unable to initialize gateway layer") | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	initNSLock(false) // Enable local namespace lock.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	router := mux.NewRouter().SkipClean(true) | 
					
						
							|  |  |  | 	registerGatewayAPIRouter(router, newObject) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var handlerFns = []HandlerFunc{ | 
					
						
							| 
									
										
										
										
											2017-04-29 08:17:18 +08:00
										 |  |  | 		// Validate all the incoming paths.
 | 
					
						
							|  |  |  | 		setPathValidityHandler, | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 		// Limits all requests size to a maximum fixed limit
 | 
					
						
							|  |  |  | 		setRequestSizeLimitHandler, | 
					
						
							|  |  |  | 		// Adds 'crossdomain.xml' policy handler to serve legacy flash clients.
 | 
					
						
							|  |  |  | 		setCrossDomainPolicy, | 
					
						
							|  |  |  | 		// Validates all incoming requests to have a valid date header.
 | 
					
						
							|  |  |  | 		setTimeValidityHandler, | 
					
						
							|  |  |  | 		// CORS setting for all browser API requests.
 | 
					
						
							|  |  |  | 		setCorsHandler, | 
					
						
							|  |  |  | 		// Validates all incoming URL resources, for invalid/unsupported
 | 
					
						
							|  |  |  | 		// resources client receives a HTTP error.
 | 
					
						
							|  |  |  | 		setIgnoreResourcesHandler, | 
					
						
							|  |  |  | 		// Auth handler verifies incoming authorization headers and
 | 
					
						
							|  |  |  | 		// routes them accordingly. Client receives a HTTP error for
 | 
					
						
							|  |  |  | 		// invalid/unsupported signatures.
 | 
					
						
							|  |  |  | 		setAuthHandler, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	apiServer := NewServerMux(ctx.String("address"), registerHandlers(router, handlerFns...)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-31 02:21:19 +08:00
										 |  |  | 	_, _, globalIsSSL, err = getSSLConfig() | 
					
						
							|  |  |  | 	fatalIf(err, "Invalid SSL key file") | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Start server, automatically configures TLS if certs are available.
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		cert, key := "", "" | 
					
						
							|  |  |  | 		if globalIsSSL { | 
					
						
							|  |  |  | 			cert, key = getPublicCertFile(), getPrivateKeyFile() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		aerr := apiServer.ListenAndServe(cert, key) | 
					
						
							|  |  |  | 		fatalIf(aerr, "Failed to start minio server") | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Once endpoints are finalized, initialize the new object api.
 | 
					
						
							|  |  |  | 	globalObjLayerMutex.Lock() | 
					
						
							|  |  |  | 	globalObjectAPI = newObject | 
					
						
							|  |  |  | 	globalObjLayerMutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Prints the formatted startup message once object layer is initialized.
 | 
					
						
							|  |  |  | 	if !quietFlag { | 
					
						
							|  |  |  | 		mode := "" | 
					
						
							|  |  |  | 		if gatewayBackend(backendType) == azureBackend { | 
					
						
							|  |  |  | 			mode = globalMinioModeGatewayAzure | 
					
						
							| 
									
										
										
										
											2017-04-28 02:26:00 +08:00
										 |  |  | 		} else if gatewayBackend(backendType) == s3Backend { | 
					
						
							|  |  |  | 			mode = globalMinioModeGatewayS3 | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		checkUpdate(mode) | 
					
						
							| 
									
										
										
										
											2017-04-12 06:44:27 +08:00
										 |  |  | 		apiEndpoints := getAPIEndpoints(apiServer.Addr) | 
					
						
							|  |  |  | 		printGatewayStartupMessage(apiEndpoints, accessKey, secretKey, backendType) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	<-globalServiceDoneCh | 
					
						
							|  |  |  | } |