mirror of
https://github.com/minio/minio.git
synced 2025-04-18 17:55:28 -04:00
server: handle command line and env variables at one place. (#3975)
This commit is contained in:
parent
447fdd4097
commit
2df8160f6a
30
cmd/certs.go
30
cmd/certs.go
@ -24,11 +24,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// isSSL - returns true with both cert and key exists.
|
|
||||||
func isSSL() bool {
|
|
||||||
return isFile(getPublicCertFile()) && isFile(getPrivateKeyFile())
|
|
||||||
}
|
|
||||||
|
|
||||||
func parsePublicCertFile(certFile string) (certs []*x509.Certificate, err error) {
|
func parsePublicCertFile(certFile string) (certs []*x509.Certificate, err error) {
|
||||||
var bytes []byte
|
var bytes []byte
|
||||||
|
|
||||||
@ -60,11 +55,6 @@ func parsePublicCertFile(certFile string) (certs []*x509.Certificate, err error)
|
|||||||
return certs, err
|
return certs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads certificate file and returns a list of parsed certificates.
|
|
||||||
func readCertificateChain() ([]*x509.Certificate, error) {
|
|
||||||
return parsePublicCertFile(getPublicCertFile())
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRootCAs(certsCAsDir string) (*x509.CertPool, error) {
|
func getRootCAs(certsCAsDir string) (*x509.CertPool, error) {
|
||||||
// Get all CA file names.
|
// Get all CA file names.
|
||||||
var caFiles []string
|
var caFiles []string
|
||||||
@ -100,9 +90,19 @@ func getRootCAs(certsCAsDir string) (*x509.CertPool, error) {
|
|||||||
return rootCAs, nil
|
return rootCAs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadRootCAs fetches CA files provided in minio config and adds them to globalRootCAs
|
func getSSLConfig() (publicCerts []*x509.Certificate, rootCAs *x509.CertPool, secureConn bool, err error) {
|
||||||
// Currently under Windows, there is no way to load system + user CAs at the same time
|
if !(isFile(getPublicCertFile()) && isFile(getPrivateKeyFile())) {
|
||||||
func loadRootCAs() (err error) {
|
return publicCerts, rootCAs, secureConn, err
|
||||||
globalRootCAs, err = getRootCAs(getCADir())
|
}
|
||||||
return err
|
|
||||||
|
if publicCerts, err = parsePublicCertFile(getPublicCertFile()); err != nil {
|
||||||
|
return publicCerts, rootCAs, secureConn, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if rootCAs, err = getRootCAs(getCADir()); err != nil {
|
||||||
|
return publicCerts, rootCAs, secureConn, err
|
||||||
|
}
|
||||||
|
|
||||||
|
secureConn = true
|
||||||
|
return publicCerts, rootCAs, secureConn, err
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,3 @@ func getPublicCertFile() string {
|
|||||||
func getPrivateKeyFile() string {
|
func getPrivateKeyFile() string {
|
||||||
return configDir.GetPrivateKeyFile()
|
return configDir.GetPrivateKeyFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
func isConfigFileExists() bool {
|
|
||||||
return isFile(getConfigFile())
|
|
||||||
}
|
|
||||||
|
@ -50,7 +50,7 @@ func TestServerConfigMigrateV1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize server config and check again if everything is fine
|
// Initialize server config and check again if everything is fine
|
||||||
if err := loadConfig(envParams{}); err != nil {
|
if err := loadConfig(); err != nil {
|
||||||
t.Fatalf("Unable to initialize from updated config file %s", err)
|
t.Fatalf("Unable to initialize from updated config file %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ func TestServerConfigMigrateV2toV16(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize server config and check again if everything is fine
|
// Initialize server config and check again if everything is fine
|
||||||
if err := loadConfig(envParams{}); err != nil {
|
if err := loadConfig(); err != nil {
|
||||||
t.Fatalf("Unable to initialize from updated config file %s", err)
|
t.Fatalf("Unable to initialize from updated config file %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,17 +87,17 @@ func newServerConfigV17() *serverConfigV17 {
|
|||||||
|
|
||||||
// newConfig - initialize a new server config, saves env parameters if
|
// newConfig - initialize a new server config, saves env parameters if
|
||||||
// found, otherwise use default parameters
|
// found, otherwise use default parameters
|
||||||
func newConfig(envParams envParams) error {
|
func newConfig() error {
|
||||||
// Initialize server config.
|
// Initialize server config.
|
||||||
srvCfg := newServerConfigV17()
|
srvCfg := newServerConfigV17()
|
||||||
|
|
||||||
// If env is set for a fresh start, save them to config file.
|
// If env is set for a fresh start, save them to config file.
|
||||||
if globalIsEnvCreds {
|
if globalIsEnvCreds {
|
||||||
srvCfg.SetCredential(envParams.creds)
|
srvCfg.SetCredential(globalActiveCred)
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalIsEnvBrowser {
|
if globalIsEnvBrowser {
|
||||||
srvCfg.SetBrowser(envParams.browser)
|
srvCfg.SetBrowser(globalIsBrowserEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create config path.
|
// Create config path.
|
||||||
@ -118,7 +118,7 @@ func newConfig(envParams envParams) error {
|
|||||||
|
|
||||||
// loadConfig - loads a new config from disk, overrides params from env
|
// loadConfig - loads a new config from disk, overrides params from env
|
||||||
// if found and valid
|
// if found and valid
|
||||||
func loadConfig(envParams envParams) error {
|
func loadConfig() error {
|
||||||
srvCfg := &serverConfigV17{
|
srvCfg := &serverConfigV17{
|
||||||
Region: globalMinioDefaultRegion,
|
Region: globalMinioDefaultRegion,
|
||||||
Browser: true,
|
Browser: true,
|
||||||
@ -133,15 +133,15 @@ func loadConfig(envParams envParams) error {
|
|||||||
|
|
||||||
// If env is set override the credentials from config file.
|
// If env is set override the credentials from config file.
|
||||||
if globalIsEnvCreds {
|
if globalIsEnvCreds {
|
||||||
srvCfg.SetCredential(envParams.creds)
|
srvCfg.SetCredential(globalActiveCred)
|
||||||
|
} else {
|
||||||
|
globalActiveCred = srvCfg.GetCredential()
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalIsEnvBrowser {
|
if globalIsEnvBrowser {
|
||||||
srvCfg.SetBrowser(envParams.browser)
|
srvCfg.SetBrowser(globalIsBrowserEnabled)
|
||||||
}
|
} else {
|
||||||
|
globalIsBrowserEnabled = srvCfg.GetBrowser()
|
||||||
if !srvCfg.GetBrowser() {
|
|
||||||
globalIsBrowserEnabled = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// hold the mutex lock before a new config is assigned.
|
// hold the mutex lock before a new config is assigned.
|
||||||
@ -310,20 +310,20 @@ func (s serverConfigV17) GetCredential() credential {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetBrowser set if browser is enabled.
|
// SetBrowser set if browser is enabled.
|
||||||
func (s *serverConfigV17) SetBrowser(v BrowserFlag) {
|
func (s *serverConfigV17) SetBrowser(b bool) {
|
||||||
serverConfigMu.Lock()
|
serverConfigMu.Lock()
|
||||||
defer serverConfigMu.Unlock()
|
defer serverConfigMu.Unlock()
|
||||||
|
|
||||||
// Set the new value.
|
// Set the new value.
|
||||||
s.Browser = v
|
s.Browser = BrowserFlag(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCredentials get current credentials.
|
// GetCredentials get current credentials.
|
||||||
func (s serverConfigV17) GetBrowser() BrowserFlag {
|
func (s serverConfigV17) GetBrowser() bool {
|
||||||
serverConfigMu.RLock()
|
serverConfigMu.RLock()
|
||||||
defer serverConfigMu.RUnlock()
|
defer serverConfigMu.RUnlock()
|
||||||
|
|
||||||
return s.Browser
|
return bool(s.Browser)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save config.
|
// Save config.
|
||||||
|
@ -122,7 +122,7 @@ func TestServerConfig(t *testing.T) {
|
|||||||
setConfigDir(rootPath)
|
setConfigDir(rootPath)
|
||||||
|
|
||||||
// Initialize server config.
|
// Initialize server config.
|
||||||
if err := loadConfig(envParams{}); err != nil {
|
if err := loadConfig(); err != nil {
|
||||||
t.Fatalf("Unable to initialize from updated config file %s", err)
|
t.Fatalf("Unable to initialize from updated config file %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,6 +149,8 @@ func TestServerConfigWithEnvs(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serverHandleEnvVars()
|
||||||
|
|
||||||
// Do this only once here.
|
// Do this only once here.
|
||||||
setConfigDir(rootPath)
|
setConfigDir(rootPath)
|
||||||
|
|
||||||
@ -160,7 +162,7 @@ func TestServerConfigWithEnvs(t *testing.T) {
|
|||||||
|
|
||||||
// Check if serverConfig has
|
// Check if serverConfig has
|
||||||
if serverConfig.GetBrowser() {
|
if serverConfig.GetBrowser() {
|
||||||
t.Errorf("Expecting browser `off` found %s", serverConfig.GetBrowser())
|
t.Errorf("Expecting browser is set to false found %v", serverConfig.GetBrowser())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if serverConfig has
|
// Check if serverConfig has
|
||||||
|
@ -144,6 +144,9 @@ func gatewayMain(ctx *cli.Context) {
|
|||||||
|
|
||||||
// Get quiet flag from command line argument.
|
// Get quiet flag from command line argument.
|
||||||
quietFlag := ctx.Bool("quiet") || ctx.GlobalBool("quiet")
|
quietFlag := ctx.Bool("quiet") || ctx.GlobalBool("quiet")
|
||||||
|
if quietFlag {
|
||||||
|
log.EnableQuiet()
|
||||||
|
}
|
||||||
|
|
||||||
// First argument is selected backend type.
|
// First argument is selected backend type.
|
||||||
backendType := ctx.Args().First()
|
backendType := ctx.Args().First()
|
||||||
@ -176,8 +179,8 @@ func gatewayMain(ctx *cli.Context) {
|
|||||||
|
|
||||||
apiServer := NewServerMux(ctx.String("address"), registerHandlers(router, handlerFns...))
|
apiServer := NewServerMux(ctx.String("address"), registerHandlers(router, handlerFns...))
|
||||||
|
|
||||||
// Set if we are SSL enabled S3 gateway.
|
_, _, globalIsSSL, err = getSSLConfig()
|
||||||
globalIsSSL = isSSL()
|
fatalIf(err, "Invalid SSL key file")
|
||||||
|
|
||||||
// Start server, automatically configures TLS if certs are available.
|
// Start server, automatically configures TLS if certs are available.
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -47,9 +47,7 @@ func printGatewayStartupMessage(apiEndPoints []string, accessKey, secretKey, bac
|
|||||||
// SSL is configured reads certification chain, prints
|
// SSL is configured reads certification chain, prints
|
||||||
// authority and expiry.
|
// authority and expiry.
|
||||||
if globalIsSSL {
|
if globalIsSSL {
|
||||||
certs, err := readCertificateChain()
|
printCertificateMsg(globalPublicCerts)
|
||||||
fatalIf(err, "Unable to read certificate chain")
|
|
||||||
printCertificateMsg(certs)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +109,9 @@ var (
|
|||||||
// Time when object layer was initialized on start up.
|
// Time when object layer was initialized on start up.
|
||||||
globalBootTime time.Time
|
globalBootTime time.Time
|
||||||
|
|
||||||
|
globalActiveCred credential
|
||||||
|
globalPublicCerts []*x509.Certificate
|
||||||
|
globalXLObjCacheDisabled bool
|
||||||
// Add new variable global values here.
|
// Add new variable global values here.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/url"
|
|
||||||
pathutil "path"
|
pathutil "path"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@ -38,12 +37,12 @@ type RWLocker interface {
|
|||||||
|
|
||||||
// Initialize distributed locking only in case of distributed setup.
|
// Initialize distributed locking only in case of distributed setup.
|
||||||
// Returns if the setup is distributed or not on success.
|
// Returns if the setup is distributed or not on success.
|
||||||
func initDsyncNodes(eps []*url.URL) error {
|
func initDsyncNodes() error {
|
||||||
cred := serverConfig.GetCredential()
|
cred := serverConfig.GetCredential()
|
||||||
// Initialize rpc lock client information only if this instance is a distributed setup.
|
// Initialize rpc lock client information only if this instance is a distributed setup.
|
||||||
clnts := make([]dsync.NetLocker, len(eps))
|
clnts := make([]dsync.NetLocker, len(globalEndpoints))
|
||||||
myNode := -1
|
myNode := -1
|
||||||
for index, ep := range eps {
|
for index, ep := range globalEndpoints {
|
||||||
if ep == nil {
|
if ep == nil {
|
||||||
return errInvalidArgument
|
return errInvalidArgument
|
||||||
}
|
}
|
||||||
|
@ -94,20 +94,6 @@ func checkUpdate(mode string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// envParams holds all env parameters
|
|
||||||
type envParams struct {
|
|
||||||
creds credential
|
|
||||||
browser BrowserFlag
|
|
||||||
}
|
|
||||||
|
|
||||||
func migrate() {
|
|
||||||
// Migrate config file
|
|
||||||
err := migrateConfig()
|
|
||||||
fatalIf(err, "Config migration failed.")
|
|
||||||
|
|
||||||
// Migrate other configs here.
|
|
||||||
}
|
|
||||||
|
|
||||||
func enableLoggers() {
|
func enableLoggers() {
|
||||||
fileLogTarget := serverConfig.Logger.GetFile()
|
fileLogTarget := serverConfig.Logger.GetFile()
|
||||||
if fileLogTarget.Enable {
|
if fileLogTarget.Enable {
|
||||||
@ -124,77 +110,6 @@ func enableLoggers() {
|
|||||||
log.SetConsoleTarget(consoleLogTarget)
|
log.SetConsoleTarget(consoleLogTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes a new config if it doesn't exist, else migrates any old config
|
|
||||||
// to newer config and finally loads the config to memory.
|
|
||||||
func initConfig() {
|
|
||||||
accessKey := os.Getenv("MINIO_ACCESS_KEY")
|
|
||||||
secretKey := os.Getenv("MINIO_SECRET_KEY")
|
|
||||||
|
|
||||||
var cred credential
|
|
||||||
var err error
|
|
||||||
if accessKey != "" && secretKey != "" {
|
|
||||||
cred, err = createCredential(accessKey, secretKey)
|
|
||||||
fatalIf(err, "Invalid access/secret Key set in environment.")
|
|
||||||
|
|
||||||
// credential Envs are set globally.
|
|
||||||
globalIsEnvCreds = true
|
|
||||||
}
|
|
||||||
|
|
||||||
envs := envParams{
|
|
||||||
creds: cred,
|
|
||||||
browser: BrowserFlag(true),
|
|
||||||
}
|
|
||||||
|
|
||||||
if browser := os.Getenv("MINIO_BROWSER"); browser != "" {
|
|
||||||
browserFlag, err := ParseBrowserFlag(browser)
|
|
||||||
if err != nil {
|
|
||||||
fatalIf(errors.New("invalid value"), "Unknown value ‘%s’ in MINIO_BROWSER environment variable.", browser)
|
|
||||||
}
|
|
||||||
|
|
||||||
// browser Envs are set globally, this does not represent
|
|
||||||
// if browser is turned off or on.
|
|
||||||
globalIsEnvBrowser = true
|
|
||||||
envs.browser = browserFlag
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config file does not exist, we create it fresh and return upon success.
|
|
||||||
if !isConfigFileExists() {
|
|
||||||
err := newConfig(envs)
|
|
||||||
fatalIf(err, "Unable to initialize minio config for the first time.")
|
|
||||||
log.Println("Created minio configuration file successfully at " + getConfigDir())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Migrate any old version of config / state files to newer format.
|
|
||||||
migrate()
|
|
||||||
|
|
||||||
// Validate config file
|
|
||||||
err = validateConfig()
|
|
||||||
fatalIf(err, "Unable to validate configuration file")
|
|
||||||
|
|
||||||
// Once we have migrated all the old config, now load them.
|
|
||||||
err = loadConfig(envs)
|
|
||||||
fatalIf(err, "Unable to initialize minio config")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic Minio initialization to create/load config, prepare loggers, etc..
|
|
||||||
func minioInit(ctx *cli.Context) {
|
|
||||||
// Create certs path.
|
|
||||||
fatalIf(createConfigDir(), "Unable to create \"certs\" directory.")
|
|
||||||
|
|
||||||
// Is TLS configured?.
|
|
||||||
globalIsSSL = isSSL()
|
|
||||||
|
|
||||||
// Initialize minio server config.
|
|
||||||
initConfig()
|
|
||||||
|
|
||||||
// Enable all loggers by now so we can use errorIf() and fatalIf()
|
|
||||||
enableLoggers()
|
|
||||||
|
|
||||||
// Init the error tracing module.
|
|
||||||
initError()
|
|
||||||
}
|
|
||||||
|
|
||||||
type serverCmdConfig struct {
|
type serverCmdConfig struct {
|
||||||
serverAddr string
|
serverAddr string
|
||||||
endpoints []*url.URL
|
endpoints []*url.URL
|
||||||
@ -240,18 +155,6 @@ func parseStorageEndpoints(eps []string) (endpoints []*url.URL, err error) {
|
|||||||
return endpoints, nil
|
return endpoints, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initServer initialize server config.
|
|
||||||
func initServerConfig(c *cli.Context) {
|
|
||||||
// Initialization such as config generating/loading config, enable logging, ..
|
|
||||||
minioInit(c)
|
|
||||||
|
|
||||||
// Load user supplied root CAs
|
|
||||||
fatalIf(loadRootCAs(), "Unable to load a CA files")
|
|
||||||
|
|
||||||
// Set system resources to maximum.
|
|
||||||
errorIf(setMaxResources(), "Unable to change resource limit")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate if input disks are sufficient for initializing XL.
|
// Validate if input disks are sufficient for initializing XL.
|
||||||
func checkSufficientDisks(eps []*url.URL) error {
|
func checkSufficientDisks(eps []*url.URL) error {
|
||||||
// Verify total number of disks.
|
// Verify total number of disks.
|
||||||
@ -344,21 +247,9 @@ func checkEndpointsSyntax(eps []*url.URL, disks []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure all the command line parameters are OK and exit in case of invalid parameters.
|
// Make sure all the command line parameters are OK and exit in case of invalid parameters.
|
||||||
func checkServerSyntax(c *cli.Context) {
|
func checkServerSyntax(endpoints []*url.URL, disks []string) {
|
||||||
serverAddr := c.String("address")
|
|
||||||
|
|
||||||
host, portStr, err := net.SplitHostPort(serverAddr)
|
|
||||||
fatalIf(err, "Unable to parse %s.", serverAddr)
|
|
||||||
|
|
||||||
// Verify syntax for all the XL disks.
|
|
||||||
disks := c.Args()
|
|
||||||
|
|
||||||
// Parse disks check if they comply with expected URI style.
|
|
||||||
endpoints, err := parseStorageEndpoints(disks)
|
|
||||||
fatalIf(err, "Unable to parse storage endpoints %s", strings.Join(disks, " "))
|
|
||||||
|
|
||||||
// Validate if endpoints follow the expected syntax.
|
// Validate if endpoints follow the expected syntax.
|
||||||
err = checkEndpointsSyntax(endpoints, disks)
|
err := checkEndpointsSyntax(endpoints, disks)
|
||||||
fatalIf(err, "Invalid endpoints found %s", strings.Join(disks, " "))
|
fatalIf(err, "Invalid endpoints found %s", strings.Join(disks, " "))
|
||||||
|
|
||||||
// Validate for duplicate endpoints are supplied.
|
// Validate for duplicate endpoints are supplied.
|
||||||
@ -382,25 +273,25 @@ func checkServerSyntax(c *cli.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rest of the checks applies only to distributed XL setup.
|
// Rest of the checks applies only to distributed XL setup.
|
||||||
if host != "" {
|
if globalMinioHost != "" {
|
||||||
// We are here implies --address host:port is passed, hence the user is trying
|
// We are here implies --address host:port is passed, hence the user is trying
|
||||||
// to run one minio process per export disk.
|
// to run one minio process per export disk.
|
||||||
if portStr == "" {
|
if globalMinioPort == "" {
|
||||||
fatalIf(errInvalidArgument, "Port missing, Host:Port should be specified for --address")
|
fatalIf(errInvalidArgument, "Port missing, Host:Port should be specified for --address")
|
||||||
}
|
}
|
||||||
foundCnt := 0
|
foundCnt := 0
|
||||||
for _, ep := range endpoints {
|
for _, ep := range endpoints {
|
||||||
if ep.Host == serverAddr {
|
if ep.Host == globalMinioAddr {
|
||||||
foundCnt++
|
foundCnt++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if foundCnt == 0 {
|
if foundCnt == 0 {
|
||||||
// --address host:port should be available in the XL disk list.
|
// --address host:port should be available in the XL disk list.
|
||||||
fatalIf(errInvalidArgument, "%s is not available in %s", serverAddr, strings.Join(disks, " "))
|
fatalIf(errInvalidArgument, "%s is not available in %s", globalMinioAddr, strings.Join(disks, " "))
|
||||||
}
|
}
|
||||||
if foundCnt > 1 {
|
if foundCnt > 1 {
|
||||||
// --address host:port should match exactly one entry in the XL disk list.
|
// --address host:port should match exactly one entry in the XL disk list.
|
||||||
fatalIf(errInvalidArgument, "%s matches % entries in %s", serverAddr, foundCnt, strings.Join(disks, " "))
|
fatalIf(errInvalidArgument, "%s matches % entries in %s", globalMinioAddr, foundCnt, strings.Join(disks, " "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,22 +353,23 @@ func getHostPort(address string) (host, port string, err error) {
|
|||||||
return host, port, nil
|
return host, port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// serverMain handler called for 'minio server' command.
|
func initConfig() {
|
||||||
func serverMain(c *cli.Context) {
|
// Config file does not exist, we create it fresh and return upon success.
|
||||||
if !c.Args().Present() || c.Args().First() == "help" {
|
if isFile(getConfigFile()) {
|
||||||
cli.ShowCommandHelpAndExit(c, "server", 1)
|
fatalIf(migrateConfig(), "Config migration failed.")
|
||||||
}
|
fatalIf(validateConfig(), "Unable to validate configuration file")
|
||||||
|
fatalIf(loadConfig(), "Unable to initialize minio config")
|
||||||
// Get quiet flag from command line argument.
|
} else {
|
||||||
quietFlag := c.Bool("quiet") || c.GlobalBool("quiet")
|
fatalIf(newConfig(), "Unable to initialize minio config for the first time.")
|
||||||
if quietFlag {
|
log.Println("Created minio configuration file successfully at " + getConfigDir())
|
||||||
log.EnableQuiet()
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverHandleCmdArgs(ctx *cli.Context) {
|
||||||
// Get configuration directory from command line argument.
|
// Get configuration directory from command line argument.
|
||||||
configDir := c.String("config-dir")
|
configDir := ctx.String("config-dir")
|
||||||
if !c.IsSet("config-dir") && c.GlobalIsSet("config-dir") {
|
if !ctx.IsSet("config-dir") && ctx.GlobalIsSet("config-dir") {
|
||||||
configDir = c.GlobalString("config-dir")
|
configDir = ctx.GlobalString("config-dir")
|
||||||
}
|
}
|
||||||
if configDir == "" {
|
if configDir == "" {
|
||||||
fatalIf(errors.New("empty directory"), "Configuration directory cannot be empty.")
|
fatalIf(errors.New("empty directory"), "Configuration directory cannot be empty.")
|
||||||
@ -494,35 +386,16 @@ func serverMain(c *cli.Context) {
|
|||||||
// Set configuration directory.
|
// Set configuration directory.
|
||||||
setConfigDir(configDir)
|
setConfigDir(configDir)
|
||||||
|
|
||||||
// Start profiler if env is set.
|
|
||||||
if profiler := os.Getenv("_MINIO_PROFILER"); profiler != "" {
|
|
||||||
globalProfiler = startProfiler(profiler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes server config, certs, logging and system settings.
|
|
||||||
initServerConfig(c)
|
|
||||||
|
|
||||||
// Server address.
|
// Server address.
|
||||||
serverAddr := c.String("address")
|
globalMinioAddr = ctx.String("address")
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
globalMinioHost, globalMinioPort, err = getHostPort(serverAddr)
|
globalMinioHost, globalMinioPort, err = getHostPort(globalMinioAddr)
|
||||||
fatalIf(err, "Unable to extract host and port %s", serverAddr)
|
fatalIf(err, "Unable to extract host and port %s", globalMinioAddr)
|
||||||
|
|
||||||
// Check server syntax and exit in case of errors.
|
|
||||||
// Done after globalMinioHost and globalMinioPort is set
|
|
||||||
// as parseStorageEndpoints() depends on it.
|
|
||||||
checkServerSyntax(c)
|
|
||||||
|
|
||||||
// Disks to be used in server init.
|
// Disks to be used in server init.
|
||||||
endpoints, err := parseStorageEndpoints(c.Args())
|
endpoints, err := parseStorageEndpoints(ctx.Args())
|
||||||
fatalIf(err, "Unable to parse storage endpoints %s", c.Args())
|
fatalIf(err, "Unable to parse storage endpoints %s", ctx.Args())
|
||||||
|
|
||||||
// Should exit gracefully if none of the endpoints passed
|
|
||||||
// as command line args are local to this server.
|
|
||||||
if !isAnyEndpointLocal(endpoints) {
|
|
||||||
fatalIf(errInvalidArgument, "None of the disks passed as command line args are local to this server.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort endpoints for consistent ordering across multiple
|
// Sort endpoints for consistent ordering across multiple
|
||||||
// nodes in a distributed setup. This is to avoid format.json
|
// nodes in a distributed setup. This is to avoid format.json
|
||||||
@ -530,26 +403,91 @@ func serverMain(c *cli.Context) {
|
|||||||
// on all nodes.
|
// on all nodes.
|
||||||
sort.Sort(byHostPath(endpoints))
|
sort.Sort(byHostPath(endpoints))
|
||||||
|
|
||||||
// Configure server.
|
checkServerSyntax(endpoints, ctx.Args())
|
||||||
srvConfig := serverCmdConfig{
|
|
||||||
serverAddr: serverAddr,
|
// Should exit gracefully if none of the endpoints passed
|
||||||
endpoints: endpoints,
|
// as command line args are local to this server.
|
||||||
|
if !isAnyEndpointLocal(endpoints) {
|
||||||
|
fatalIf(errInvalidArgument, "None of the disks passed as command line args are local to this server.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if endpoints are part of distributed setup.
|
// Check if endpoints are part of distributed setup.
|
||||||
globalIsDistXL = isDistributedSetup(endpoints)
|
globalIsDistXL = isDistributedSetup(endpoints)
|
||||||
|
|
||||||
// Set nodes for dsync for distributed setup.
|
|
||||||
if globalIsDistXL {
|
|
||||||
fatalIf(initDsyncNodes(endpoints), "Unable to initialize distributed locking clients")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set globalIsXL if erasure code backend is about to be
|
// Set globalIsXL if erasure code backend is about to be
|
||||||
// initialized for the given endpoints.
|
// initialized for the given endpoints.
|
||||||
if len(endpoints) > 1 {
|
if len(endpoints) > 1 {
|
||||||
globalIsXL = true
|
globalIsXL = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set endpoints of []*url.URL type to globalEndpoints.
|
||||||
|
globalEndpoints = endpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverHandleEnvVars() {
|
||||||
|
// Start profiler if env is set.
|
||||||
|
if profiler := os.Getenv("_MINIO_PROFILER"); profiler != "" {
|
||||||
|
globalProfiler = startProfiler(profiler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if object cache is disabled.
|
||||||
|
globalXLObjCacheDisabled = strings.EqualFold(os.Getenv("_MINIO_CACHE"), "off")
|
||||||
|
|
||||||
|
accessKey := os.Getenv("MINIO_ACCESS_KEY")
|
||||||
|
secretKey := os.Getenv("MINIO_SECRET_KEY")
|
||||||
|
if accessKey != "" && secretKey != "" {
|
||||||
|
cred, err := createCredential(accessKey, secretKey)
|
||||||
|
fatalIf(err, "Invalid access/secret Key set in environment.")
|
||||||
|
|
||||||
|
// credential Envs are set globally.
|
||||||
|
globalIsEnvCreds = true
|
||||||
|
globalActiveCred = cred
|
||||||
|
}
|
||||||
|
|
||||||
|
if browser := os.Getenv("MINIO_BROWSER"); browser != "" {
|
||||||
|
browserFlag, err := ParseBrowserFlag(browser)
|
||||||
|
if err != nil {
|
||||||
|
fatalIf(errors.New("invalid value"), "Unknown value ‘%s’ in MINIO_BROWSER environment variable.", browser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// browser Envs are set globally, this does not represent
|
||||||
|
// if browser is turned off or on.
|
||||||
|
globalIsEnvBrowser = true
|
||||||
|
globalIsBrowserEnabled = bool(browserFlag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// serverMain handler called for 'minio server' command.
|
||||||
|
func serverMain(ctx *cli.Context) {
|
||||||
|
if !ctx.Args().Present() || ctx.Args().First() == "help" {
|
||||||
|
cli.ShowCommandHelpAndExit(ctx, "server", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get quiet flag from command line argument.
|
||||||
|
quietFlag := ctx.Bool("quiet") || ctx.GlobalBool("quiet")
|
||||||
|
if quietFlag {
|
||||||
|
log.EnableQuiet()
|
||||||
|
}
|
||||||
|
|
||||||
|
serverHandleCmdArgs(ctx)
|
||||||
|
serverHandleEnvVars()
|
||||||
|
|
||||||
|
// Create certs path.
|
||||||
|
fatalIf(createConfigDir(), "Unable to create configuration directories.")
|
||||||
|
|
||||||
|
initConfig()
|
||||||
|
|
||||||
|
// Enable loggers as per configuration file.
|
||||||
|
enableLoggers()
|
||||||
|
|
||||||
|
// Init the error tracing module.
|
||||||
|
initError()
|
||||||
|
|
||||||
|
// Check and load SSL certificates.
|
||||||
|
var err error
|
||||||
|
globalPublicCerts, globalRootCAs, globalIsSSL, err = getSSLConfig()
|
||||||
|
fatalIf(err, "Invalid SSL key file")
|
||||||
|
|
||||||
if !quietFlag {
|
if !quietFlag {
|
||||||
// Check for new updates from dl.minio.io.
|
// Check for new updates from dl.minio.io.
|
||||||
mode := globalMinioModeFS
|
mode := globalMinioModeFS
|
||||||
@ -562,32 +500,43 @@ func serverMain(c *cli.Context) {
|
|||||||
checkUpdate(mode)
|
checkUpdate(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set system resources to maximum.
|
||||||
|
errorIf(setMaxResources(), "Unable to change resource limit")
|
||||||
|
|
||||||
|
// Set nodes for dsync for distributed setup.
|
||||||
|
if globalIsDistXL {
|
||||||
|
fatalIf(initDsyncNodes(), "Unable to initialize distributed locking clients")
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize name space lock.
|
// Initialize name space lock.
|
||||||
initNSLock(globalIsDistXL)
|
initNSLock(globalIsDistXL)
|
||||||
|
|
||||||
|
// Configure server.
|
||||||
|
srvConfig := serverCmdConfig{
|
||||||
|
serverAddr: globalMinioAddr,
|
||||||
|
endpoints: globalEndpoints,
|
||||||
|
}
|
||||||
|
|
||||||
// Configure server.
|
// Configure server.
|
||||||
handler, err := configureServerHandler(srvConfig)
|
handler, err := configureServerHandler(srvConfig)
|
||||||
fatalIf(err, "Unable to configure one of server's RPC services.")
|
fatalIf(err, "Unable to configure one of server's RPC services.")
|
||||||
|
|
||||||
// Initialize a new HTTP server.
|
// Initialize a new HTTP server.
|
||||||
apiServer := NewServerMux(serverAddr, handler)
|
apiServer := NewServerMux(globalMinioAddr, handler)
|
||||||
|
|
||||||
// Set the global minio addr for this server.
|
// Set the global minio addr for this server.
|
||||||
globalMinioAddr = getLocalAddress(srvConfig)
|
globalMinioAddr = getLocalAddress(srvConfig)
|
||||||
|
|
||||||
// Initialize S3 Peers inter-node communication only in distributed setup.
|
// Initialize S3 Peers inter-node communication only in distributed setup.
|
||||||
initGlobalS3Peers(endpoints)
|
initGlobalS3Peers(globalEndpoints)
|
||||||
|
|
||||||
// Initialize Admin Peers inter-node communication only in distributed setup.
|
// Initialize Admin Peers inter-node communication only in distributed setup.
|
||||||
initGlobalAdminPeers(endpoints)
|
initGlobalAdminPeers(globalEndpoints)
|
||||||
|
|
||||||
// Determine API endpoints where we are going to serve the S3 API from.
|
// Determine API endpoints where we are going to serve the S3 API from.
|
||||||
apiEndPoints, err := finalizeAPIEndpoints(apiServer.Addr)
|
globalAPIEndpoints, err = finalizeAPIEndpoints(apiServer.Addr)
|
||||||
fatalIf(err, "Unable to finalize API endpoints for %s", apiServer.Addr)
|
fatalIf(err, "Unable to finalize API endpoints for %s", apiServer.Addr)
|
||||||
|
|
||||||
// Set the global API endpoints value.
|
|
||||||
globalAPIEndpoints = apiEndPoints
|
|
||||||
|
|
||||||
// Start server, automatically configures TLS if certs are available.
|
// Start server, automatically configures TLS if certs are available.
|
||||||
go func() {
|
go func() {
|
||||||
cert, key := "", ""
|
cert, key := "", ""
|
||||||
@ -597,9 +546,6 @@ func serverMain(c *cli.Context) {
|
|||||||
fatalIf(apiServer.ListenAndServe(cert, key), "Failed to start minio server.")
|
fatalIf(apiServer.ListenAndServe(cert, key), "Failed to start minio server.")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Set endpoints of []*url.URL type to globalEndpoints.
|
|
||||||
globalEndpoints = endpoints
|
|
||||||
|
|
||||||
newObject, err := newObjectLayer(srvConfig)
|
newObject, err := newObjectLayer(srvConfig)
|
||||||
fatalIf(err, "Initializing object layer failed")
|
fatalIf(err, "Initializing object layer failed")
|
||||||
|
|
||||||
@ -608,9 +554,7 @@ func serverMain(c *cli.Context) {
|
|||||||
globalObjLayerMutex.Unlock()
|
globalObjLayerMutex.Unlock()
|
||||||
|
|
||||||
// Prints the formatted startup message once object layer is initialized.
|
// Prints the formatted startup message once object layer is initialized.
|
||||||
if !quietFlag {
|
printStartupMessage(globalAPIEndpoints)
|
||||||
printStartupMessage(apiEndPoints)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set uptime time after object layer has initialized.
|
// Set uptime time after object layer has initialized.
|
||||||
globalBootTime = UTCNow()
|
globalBootTime = UTCNow()
|
||||||
|
@ -18,13 +18,9 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/minio/cli"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetListenIPs(t *testing.T) {
|
func TestGetListenIPs(t *testing.T) {
|
||||||
@ -361,38 +357,6 @@ func TestCheckEndpointsSyntax(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests check server syntax.
|
|
||||||
func TestCheckServerSyntax(t *testing.T) {
|
|
||||||
app := cli.NewApp()
|
|
||||||
app.Commands = []cli.Command{serverCmd}
|
|
||||||
serverFlagSet := flag.NewFlagSet("server", 0)
|
|
||||||
serverFlagSet.String("address", ":9000", "")
|
|
||||||
ctx := cli.NewContext(app, serverFlagSet, nil)
|
|
||||||
|
|
||||||
disksGen := func(n int) []string {
|
|
||||||
disks, err := getRandomDisks(n)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to initialie disks %s", err)
|
|
||||||
}
|
|
||||||
return disks
|
|
||||||
}
|
|
||||||
testCases := [][]string{
|
|
||||||
disksGen(1),
|
|
||||||
disksGen(4),
|
|
||||||
disksGen(8),
|
|
||||||
disksGen(16),
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, disks := range testCases {
|
|
||||||
err := serverFlagSet.Parse(disks)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Test %d failed to parse arguments %s", i+1, disks)
|
|
||||||
}
|
|
||||||
defer removeRoots(disks)
|
|
||||||
checkServerSyntax(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsDistributedSetup(t *testing.T) {
|
func TestIsDistributedSetup(t *testing.T) {
|
||||||
var testCases []struct {
|
var testCases []struct {
|
||||||
disks []string
|
disks []string
|
||||||
@ -452,37 +416,6 @@ func TestIsDistributedSetup(t *testing.T) {
|
|||||||
globalMinioHost = ""
|
globalMinioHost = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests init server.
|
|
||||||
func TestInitServer(t *testing.T) {
|
|
||||||
app := cli.NewApp()
|
|
||||||
app.Commands = []cli.Command{serverCmd}
|
|
||||||
serverFlagSet := flag.NewFlagSet("server", 0)
|
|
||||||
serverFlagSet.String("address", ":9000", "")
|
|
||||||
ctx := cli.NewContext(app, serverFlagSet, nil)
|
|
||||||
|
|
||||||
root, err := newTestConfig(globalMinioDefaultRegion)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("Failed to set up test config")
|
|
||||||
}
|
|
||||||
defer removeAll(root)
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
envVar string
|
|
||||||
val string
|
|
||||||
}{
|
|
||||||
{"MINIO_ACCESS_KEY", "abcd1"},
|
|
||||||
{"MINIO_SECRET_KEY", "abcd12345"},
|
|
||||||
}
|
|
||||||
for i, test := range testCases {
|
|
||||||
tErr := os.Setenv(test.envVar, test.val)
|
|
||||||
if tErr != nil {
|
|
||||||
t.Fatalf("Test %d failed with %v", i+1, tErr)
|
|
||||||
}
|
|
||||||
initServerConfig(ctx)
|
|
||||||
os.Unsetenv(test.envVar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests isAnyEndpointLocal function with inputs such that it returns true and false respectively.
|
// Tests isAnyEndpointLocal function with inputs such that it returns true and false respectively.
|
||||||
func TestIsAnyEndpointLocal(t *testing.T) {
|
func TestIsAnyEndpointLocal(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
|
@ -61,9 +61,7 @@ func printStartupMessage(apiEndPoints []string) {
|
|||||||
// SSL is configured reads certification chain, prints
|
// SSL is configured reads certification chain, prints
|
||||||
// authority and expiry.
|
// authority and expiry.
|
||||||
if globalIsSSL {
|
if globalIsSSL {
|
||||||
certs, err := readCertificateChain()
|
printCertificateMsg(globalPublicCerts)
|
||||||
fatalIf(err, "Unable to read certificate chain.")
|
|
||||||
printCertificateMsg(certs)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,7 +522,7 @@ func newTestConfig(bucketLocation string) (rootPath string, err error) {
|
|||||||
setConfigDir(rootPath)
|
setConfigDir(rootPath)
|
||||||
|
|
||||||
// Initialize server config.
|
// Initialize server config.
|
||||||
if err = newConfig(envParams{}); err != nil {
|
if err = newConfig(); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,10 +18,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
humanize "github.com/dustin/go-humanize"
|
humanize "github.com/dustin/go-humanize"
|
||||||
@ -115,9 +113,6 @@ func newXLObjects(storageDisks []StorageAPI) (ObjectLayer, error) {
|
|||||||
// Initialize list pool.
|
// Initialize list pool.
|
||||||
listPool := newTreeWalkPool(globalLookupTimeout)
|
listPool := newTreeWalkPool(globalLookupTimeout)
|
||||||
|
|
||||||
// Check if object cache is disabled.
|
|
||||||
objCacheDisabled := strings.EqualFold(os.Getenv("_MINIO_CACHE"), "off")
|
|
||||||
|
|
||||||
// Initialize xl objects.
|
// Initialize xl objects.
|
||||||
xl := &xlObjects{
|
xl := &xlObjects{
|
||||||
mutex: &sync.Mutex{},
|
mutex: &sync.Mutex{},
|
||||||
@ -129,7 +124,7 @@ func newXLObjects(storageDisks []StorageAPI) (ObjectLayer, error) {
|
|||||||
|
|
||||||
// Get cache size if _MINIO_CACHE environment variable is set.
|
// Get cache size if _MINIO_CACHE environment variable is set.
|
||||||
var maxCacheSize uint64
|
var maxCacheSize uint64
|
||||||
if !objCacheDisabled {
|
if !globalXLObjCacheDisabled {
|
||||||
maxCacheSize, err = GetMaxCacheSize()
|
maxCacheSize, err = GetMaxCacheSize()
|
||||||
errorIf(err, "Unable to get maximum cache size")
|
errorIf(err, "Unable to get maximum cache size")
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user