2017-03-16 15:21:58 -04:00
|
|
|
/*
|
2018-02-28 23:13:33 -05:00
|
|
|
* Minio Cloud Storage, (C) 2017, 2018 Minio, Inc.
|
2017-03-16 15:21:58 -04: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-04-05 18:04:40 -04:00
|
|
|
"context"
|
2017-03-16 15:21:58 -04:00
|
|
|
"fmt"
|
2018-09-06 19:42:33 -04:00
|
|
|
"net"
|
2017-04-11 20:44:26 -04:00
|
|
|
"net/url"
|
2017-07-12 19:33:21 -04:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
2017-04-11 20:44:26 -04:00
|
|
|
"strings"
|
2017-07-12 19:33:21 -04:00
|
|
|
"syscall"
|
2017-06-05 18:18:03 -04:00
|
|
|
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
"github.com/minio/cli"
|
2018-04-21 22:23:54 -04:00
|
|
|
xhttp "github.com/minio/minio/cmd/http"
|
2018-04-05 18:04:40 -04:00
|
|
|
"github.com/minio/minio/cmd/logger"
|
2018-05-31 15:30:15 -04:00
|
|
|
"github.com/minio/minio/pkg/certs"
|
2017-03-16 15:21:58 -04:00
|
|
|
)
|
|
|
|
|
2018-05-21 14:11:57 -04:00
|
|
|
func init() {
|
2018-06-18 15:04:46 -04:00
|
|
|
logger.Init(GOPATH, GOROOT)
|
2018-05-21 14:11:57 -04:00
|
|
|
logger.RegisterUIError(fmtError)
|
|
|
|
}
|
|
|
|
|
2017-06-09 22:50:51 -04:00
|
|
|
var (
|
|
|
|
gatewayCmd = cli.Command{
|
|
|
|
Name: "gateway",
|
2018-11-20 20:35:33 -05:00
|
|
|
Usage: "start object storage gateway",
|
2017-06-09 22:50:51 -04:00
|
|
|
Flags: append(serverFlags, globalFlags...),
|
|
|
|
HideHelpCommand: true,
|
|
|
|
}
|
|
|
|
)
|
2017-06-09 02:28:45 -04:00
|
|
|
|
2017-10-27 18:07:46 -04:00
|
|
|
// RegisterGatewayCommand registers a new command for gateway.
|
|
|
|
func RegisterGatewayCommand(cmd cli.Command) error {
|
2017-12-05 20:58:09 -05:00
|
|
|
cmd.Flags = append(append(cmd.Flags, append(cmd.Flags, serverFlags...)...), globalFlags...)
|
2017-10-27 18:07:46 -04:00
|
|
|
gatewayCmd.Subcommands = append(gatewayCmd.Subcommands, cmd)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-12-05 20:58:09 -05:00
|
|
|
// ParseGatewayEndpoint - Return endpoint.
|
|
|
|
func ParseGatewayEndpoint(arg string) (endPoint string, secure bool, err error) {
|
2017-04-11 20:44:26 -04:00
|
|
|
schemeSpecified := len(strings.Split(arg, "://")) > 1
|
|
|
|
if !schemeSpecified {
|
|
|
|
// Default connection will be "secure".
|
|
|
|
arg = "https://" + arg
|
|
|
|
}
|
2017-04-27 14:26:00 -04:00
|
|
|
|
2017-04-11 20:44:26 -04: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-12-05 20:58:09 -05:00
|
|
|
// ValidateGatewayArguments - Validate gateway arguments.
|
|
|
|
func ValidateGatewayArguments(serverAddr, endpointAddr string) error {
|
2017-06-08 14:20:56 -04:00
|
|
|
if err := CheckLocalServerAddr(serverAddr); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if endpointAddr != "" {
|
|
|
|
// Reject the endpoint if it points to the gateway handler itself.
|
|
|
|
sameTarget, err := sameLocalAddrs(endpointAddr, serverAddr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if sameTarget {
|
2017-11-25 14:58:29 -05:00
|
|
|
return fmt.Errorf("endpoint points to the local gateway")
|
2017-06-08 14:20:56 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-12-05 20:58:09 -05:00
|
|
|
// StartGateway - handler for 'minio gateway <name>'.
|
|
|
|
func StartGateway(ctx *cli.Context, gw Gateway) {
|
|
|
|
if gw == nil {
|
2018-05-09 18:11:24 -04:00
|
|
|
logger.FatalIf(errUnexpected, "Gateway implementation not initialized")
|
2017-12-05 20:58:09 -05:00
|
|
|
}
|
|
|
|
|
2018-05-08 22:04:36 -04:00
|
|
|
// Disable logging until gateway initialization is complete, any
|
|
|
|
// error during initialization will be shown as a fatal message
|
|
|
|
logger.Disable = true
|
|
|
|
|
2017-12-05 20:58:09 -05:00
|
|
|
// Validate if we have access, secret set through environment.
|
|
|
|
gatewayName := gw.Name()
|
|
|
|
if ctx.Args().First() == "help" {
|
|
|
|
cli.ShowCommandHelpAndExit(ctx, gatewayName, 1)
|
|
|
|
}
|
|
|
|
|
2018-01-17 10:24:46 -05:00
|
|
|
// Get "json" flag from command line argument and
|
|
|
|
// enable json and quite modes if jason flag is turned on.
|
2018-02-28 23:13:33 -05:00
|
|
|
jsonFlag := ctx.IsSet("json") || ctx.GlobalIsSet("json")
|
2018-01-17 10:24:46 -05:00
|
|
|
if jsonFlag {
|
2018-04-05 18:04:40 -04:00
|
|
|
logger.EnableJSON()
|
2018-01-17 10:24:46 -05:00
|
|
|
}
|
|
|
|
|
2017-03-16 15:21:58 -04:00
|
|
|
// Get quiet flag from command line argument.
|
2018-02-28 23:13:33 -05:00
|
|
|
quietFlag := ctx.IsSet("quiet") || ctx.GlobalIsSet("quiet")
|
2017-03-30 14:21:19 -04:00
|
|
|
if quietFlag {
|
2018-04-05 18:04:40 -04:00
|
|
|
logger.EnableQuiet()
|
2017-03-30 14:21:19 -04:00
|
|
|
}
|
2017-03-16 15:21:58 -04:00
|
|
|
|
2017-07-20 19:39:11 -04:00
|
|
|
// Fetch address option
|
|
|
|
gatewayAddr := ctx.GlobalString("address")
|
|
|
|
if gatewayAddr == ":"+globalMinioPort {
|
|
|
|
gatewayAddr = ctx.String("address")
|
|
|
|
}
|
|
|
|
|
2017-06-09 22:50:51 -04:00
|
|
|
// Handle common command args.
|
|
|
|
handleCommonCmdArgs(ctx)
|
|
|
|
|
2018-09-06 19:42:33 -04:00
|
|
|
// Get port to listen on from gateway address
|
2018-11-26 12:49:38 -05:00
|
|
|
var pErr error
|
|
|
|
_, globalMinioPort, pErr = net.SplitHostPort(gatewayAddr)
|
2018-09-06 19:42:33 -04:00
|
|
|
if pErr != nil {
|
|
|
|
logger.FatalIf(pErr, "Unable to start gateway")
|
|
|
|
}
|
|
|
|
|
2018-08-18 00:06:36 -04:00
|
|
|
// On macOS, if a process already listens on LOCALIPADDR:PORT, net.Listen() falls back
|
|
|
|
// to IPv6 address ie minio will start listening on IPv6 address whereas another
|
|
|
|
// (non-)minio process is listening on IPv4 of given port.
|
|
|
|
// To avoid this error situation we check for port availability.
|
2018-11-26 12:49:38 -05:00
|
|
|
logger.FatalIf(checkPortAvailability(globalMinioPort), "Unable to start the gateway")
|
2018-08-18 00:06:36 -04:00
|
|
|
|
2017-06-09 22:50:51 -04:00
|
|
|
// Create certs path.
|
2018-05-09 18:11:24 -04:00
|
|
|
logger.FatalIf(createConfigDir(), "Unable to create configuration directories")
|
2017-06-09 22:50:51 -04:00
|
|
|
|
2018-10-27 20:51:00 -04:00
|
|
|
// Check and load TLS certificates.
|
2017-06-09 22:50:51 -04:00
|
|
|
var err error
|
2018-10-27 20:51:00 -04:00
|
|
|
globalPublicCerts, globalTLSCerts, globalIsSSL, err = getTLSConfig()
|
|
|
|
logger.FatalIf(err, "Invalid TLS certificate file")
|
|
|
|
|
|
|
|
// Check and load Root CAs.
|
|
|
|
globalRootCAs, err = getRootCAs(getCADir())
|
|
|
|
logger.FatalIf(err, "Failed to read root CAs (%v)", err)
|
2017-03-31 01:26:24 -04:00
|
|
|
|
2018-10-29 14:14:12 -04:00
|
|
|
// Handle common env vars.
|
|
|
|
handleCommonEnvVars()
|
|
|
|
|
|
|
|
// Validate if we have access, secret set through environment.
|
|
|
|
if !globalIsEnvCreds {
|
|
|
|
logger.Fatal(uiErrEnvCredentialsMissingGateway(nil), "Unable to start gateway")
|
|
|
|
}
|
|
|
|
|
2017-12-24 09:39:30 -05:00
|
|
|
// Set system resources to maximum.
|
2018-04-05 18:04:40 -04:00
|
|
|
logger.LogIf(context.Background(), setMaxResources())
|
2017-12-24 09:39:30 -05:00
|
|
|
|
2017-05-22 23:02:58 -04:00
|
|
|
initNSLock(false) // Enable local namespace lock.
|
|
|
|
|
2017-03-16 15:21:58 -04:00
|
|
|
router := mux.NewRouter().SkipClean(true)
|
2017-06-01 12:43:20 -04:00
|
|
|
|
2018-10-17 20:25:16 -04:00
|
|
|
if globalEtcdClient != nil {
|
|
|
|
// Enable STS router if etcd is enabled.
|
|
|
|
registerSTSRouter(router)
|
|
|
|
|
|
|
|
// Enable admin router if etcd is enabled.
|
|
|
|
registerAdminRouter(router)
|
|
|
|
}
|
|
|
|
|
2018-04-04 22:07:54 -04:00
|
|
|
// Add healthcheck router
|
|
|
|
registerHealthCheckRouter(router)
|
|
|
|
|
2018-05-30 00:43:46 -04:00
|
|
|
// Add server metrics router
|
|
|
|
registerMetricsRouter(router)
|
|
|
|
|
2017-06-01 12:43:20 -04:00
|
|
|
// Register web router when its enabled.
|
|
|
|
if globalIsBrowserEnabled {
|
2018-04-05 18:04:40 -04:00
|
|
|
logger.FatalIf(registerWebRouter(router), "Unable to configure web browser")
|
2017-06-01 12:43:20 -04:00
|
|
|
}
|
2017-03-16 15:21:58 -04:00
|
|
|
|
2018-04-04 22:07:54 -04:00
|
|
|
// Add API router.
|
|
|
|
registerAPIRouter(router)
|
2017-03-16 15:21:58 -04:00
|
|
|
|
2018-12-03 03:32:14 -05:00
|
|
|
// Dummy endpoint representing gateway instance.
|
|
|
|
globalEndpoints = []Endpoint{{
|
|
|
|
URL: &url.URL{Path: "/minio/gateway"},
|
|
|
|
IsLocal: true,
|
|
|
|
}}
|
|
|
|
|
|
|
|
// Initialize Admin Peers.
|
|
|
|
initGlobalAdminPeers(globalEndpoints)
|
|
|
|
|
2018-05-31 15:30:15 -04:00
|
|
|
var getCert certs.GetCertificateFunc
|
|
|
|
if globalTLSCerts != nil {
|
|
|
|
getCert = globalTLSCerts.GetCertificate
|
|
|
|
}
|
|
|
|
|
2018-06-25 16:51:49 -04:00
|
|
|
globalHTTPServer = xhttp.NewServer([]string{gatewayAddr}, criticalErrorHandler{registerHandlers(router, globalHandlers...)}, getCert)
|
2018-05-30 00:43:46 -04:00
|
|
|
globalHTTPServer.UpdateBytesReadFunc = globalConnStats.incInputBytes
|
|
|
|
globalHTTPServer.UpdateBytesWrittenFunc = globalConnStats.incOutputBytes
|
2017-03-16 15:21:58 -04:00
|
|
|
go func() {
|
2017-07-12 19:33:21 -04:00
|
|
|
globalHTTPServerErrorCh <- globalHTTPServer.Start()
|
2017-03-16 15:21:58 -04:00
|
|
|
}()
|
|
|
|
|
2017-07-12 19:33:21 -04:00
|
|
|
signal.Notify(globalOSSignalCh, os.Interrupt, syscall.SIGTERM)
|
|
|
|
|
2018-05-31 15:30:15 -04:00
|
|
|
newObject, err := gw.NewGatewayLayer(globalServerConfig.GetCredential())
|
|
|
|
if err != nil {
|
|
|
|
// Stop watching for any certificate changes.
|
|
|
|
globalTLSCerts.Stop()
|
|
|
|
|
|
|
|
globalHTTPServer.Shutdown()
|
|
|
|
logger.FatalIf(err, "Unable to initialize gateway backend")
|
|
|
|
}
|
|
|
|
|
2018-10-09 17:00:01 -04:00
|
|
|
// Create a new config system.
|
|
|
|
globalConfigSys = NewConfigSys()
|
2018-12-05 17:03:42 -05:00
|
|
|
if globalEtcdClient != nil && gatewayName == "nas" {
|
2018-12-03 03:32:14 -05:00
|
|
|
// Initialize server config.
|
|
|
|
_ = globalConfigSys.Init(newObject)
|
|
|
|
} else {
|
|
|
|
// Initialize server config.
|
|
|
|
srvCfg := newServerConfig()
|
|
|
|
|
|
|
|
// Override any values from ENVs.
|
|
|
|
srvCfg.loadFromEnvs()
|
|
|
|
|
|
|
|
// Load values to cached global values.
|
|
|
|
srvCfg.loadToCachedConfigs()
|
|
|
|
|
|
|
|
// hold the mutex lock before a new config is assigned.
|
|
|
|
globalServerConfigMu.Lock()
|
|
|
|
globalServerConfig = srvCfg
|
|
|
|
globalServerConfigMu.Unlock()
|
|
|
|
}
|
2018-10-09 17:00:01 -04:00
|
|
|
|
2018-10-12 15:25:59 -04:00
|
|
|
// Load logger subsystem
|
|
|
|
loadLoggers()
|
|
|
|
|
|
|
|
// This is only to uniquely identify each gateway deployments.
|
2018-11-19 17:47:03 -05:00
|
|
|
globalDeploymentID = os.Getenv("MINIO_GATEWAY_DEPLOYMENT_ID")
|
2018-10-12 15:25:59 -04:00
|
|
|
|
2018-10-09 17:00:01 -04:00
|
|
|
var cacheConfig = globalServerConfig.GetCacheConfig()
|
|
|
|
if len(cacheConfig.Drives) > 0 {
|
|
|
|
var err error
|
|
|
|
// initialize the new disk cache objects.
|
|
|
|
globalCacheObjectAPI, err = newServerCacheObjects(cacheConfig)
|
|
|
|
logger.FatalIf(err, "Unable to initialize disk caching")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Re-enable logging
|
|
|
|
logger.Disable = false
|
|
|
|
|
|
|
|
// Create new IAM system.
|
|
|
|
globalIAMSys = NewIAMSys()
|
2018-10-12 14:32:18 -04:00
|
|
|
if globalEtcdClient != nil {
|
|
|
|
// Initialize IAM sys.
|
2018-12-03 03:32:14 -05:00
|
|
|
_ = globalIAMSys.Init(newObject)
|
2018-10-12 14:32:18 -04:00
|
|
|
}
|
2018-10-09 17:00:01 -04:00
|
|
|
|
|
|
|
// Create new policy system.
|
|
|
|
globalPolicySys = NewPolicySys()
|
|
|
|
|
|
|
|
// Initialize policy system.
|
2018-08-03 18:12:18 -04:00
|
|
|
go globalPolicySys.Init(newObject)
|
2018-06-27 02:59:48 -04:00
|
|
|
|
2018-10-09 17:00:01 -04:00
|
|
|
// Create new notification system.
|
|
|
|
globalNotificationSys = NewNotificationSys(globalServerConfig, globalEndpoints)
|
2018-12-05 17:03:42 -05:00
|
|
|
if globalEtcdClient != nil && newObject.IsNotificationSupported() {
|
2018-12-03 03:32:14 -05:00
|
|
|
_ = globalNotificationSys.Init(newObject)
|
|
|
|
}
|
2017-03-16 15:21:58 -04: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 {
|
2017-10-27 18:07:46 -04:00
|
|
|
mode := globalMinioModeGatewayPrefix + gatewayName
|
2017-06-09 22:50:51 -04:00
|
|
|
// Check update mode.
|
2017-03-16 15:21:58 -04:00
|
|
|
checkUpdate(mode)
|
2017-06-09 22:50:51 -04:00
|
|
|
|
2017-12-05 20:58:09 -05:00
|
|
|
// Print a warning message if gateway is not ready for production before the startup banner.
|
|
|
|
if !gw.Production() {
|
2018-04-13 14:57:05 -04:00
|
|
|
logger.StartupMessage(colorYellow(" *** Warning: Not Ready for Production ***"))
|
2017-12-05 20:58:09 -05:00
|
|
|
}
|
|
|
|
|
2017-06-09 22:50:51 -04:00
|
|
|
// Print gateway startup message.
|
2017-10-27 18:07:46 -04:00
|
|
|
printGatewayStartupMessage(getAPIEndpoints(gatewayAddr), gatewayName)
|
2017-03-16 15:21:58 -04:00
|
|
|
}
|
|
|
|
|
2017-07-12 19:33:21 -04:00
|
|
|
handleSignals()
|
2017-03-16 15:21:58 -04:00
|
|
|
}
|