Cleanup ui-errors and print proper error messages (#8068)

* Cleanup ui-errors and print proper error messages

Change HELP to HINT instead, handle more error
cases when starting up MinIO. One such is related
to #8048

* Apply suggestions from code review
This commit is contained in:
Harshavardhana 2019-08-12 21:25:34 -07:00 committed by GitHub
parent 8ce424bacd
commit bf8ec8ad73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 55 additions and 40 deletions

View File

@ -61,6 +61,9 @@ func verifyObjectLayerFeatures(name string, objAPI ObjectLayer) {
func checkUpdate(mode string) { func checkUpdate(mode string) {
// Its OK to ignore any errors during doUpdate() here. // Its OK to ignore any errors during doUpdate() here.
if updateMsg, _, currentReleaseTime, latestReleaseTime, err := getUpdateInfo(2*time.Second, mode); err == nil { if updateMsg, _, currentReleaseTime, latestReleaseTime, err := getUpdateInfo(2*time.Second, mode); err == nil {
if updateMsg == "" {
return
}
if globalInplaceUpdateDisabled { if globalInplaceUpdateDisabled {
logger.StartupMessage(updateMsg) logger.StartupMessage(updateMsg)
} else { } else {

View File

@ -1,5 +1,5 @@
/* /*
* MinIO Cloud Storage, (C) 2015, 2016, 2017, 2018 MinIO, Inc. * MinIO Cloud Storage, (C) 2015-2019 MinIO, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -377,7 +377,7 @@ func serverMain(ctx *cli.Context) {
// Initialize notification system. // Initialize notification system.
if err = globalNotificationSys.Init(newObject); err != nil { if err = globalNotificationSys.Init(newObject); err != nil {
logger.LogIf(context.Background(), err) logger.Fatal(err, "Unable to initialize notification system")
} }
// Verify if object layer supports // Verify if object layer supports

View File

@ -1,5 +1,5 @@
/* /*
* MinIO Cloud Storage, (C) 2015, 2016, 2017, 2018 MinIO, Inc. * MinIO Cloud Storage, (C) 2015-2019 MinIO, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,13 +26,13 @@ import (
func handleSignals() { func handleSignals() {
// Custom exit function // Custom exit function
exit := func(state bool) { exit := func(success bool) {
// If global profiler is set stop before we exit. // If global profiler is set stop before we exit.
if globalProfiler != nil { if globalProfiler != nil {
globalProfiler.Stop() globalProfiler.Stop()
} }
if state { if success {
os.Exit(0) os.Exit(0)
} }
@ -66,13 +66,13 @@ func handleSignals() {
for { for {
select { select {
case err := <-globalHTTPServerErrorCh: case err := <-globalHTTPServerErrorCh:
logger.LogIf(context.Background(), err)
var oerr error
if objAPI := newObjectLayerFn(); objAPI != nil { if objAPI := newObjectLayerFn(); objAPI != nil {
oerr = objAPI.Shutdown(context.Background()) objAPI.Shutdown(context.Background())
} }
if err != nil {
exit(err == nil && oerr == nil) logger.Fatal(err, "Unable to start MinIO server")
}
exit(true)
case osSignal := <-globalOSSignalCh: case osSignal := <-globalOSSignalCh:
logger.Info("Exiting on signal: %s", strings.ToUpper(osSignal.String())) logger.Info("Exiting on signal: %s", strings.ToUpper(osSignal.String()))
exit(stopProcess()) exit(stopProcess())

View File

@ -1,5 +1,5 @@
/* /*
* MinIO Cloud Storage, (C) 2018 MinIO, Inc. * MinIO Cloud Storage, (C) 2018-2019 MinIO, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,6 +21,7 @@ import (
"io" "io"
"net" "net"
"os" "os"
"syscall"
) )
// uiErr is a structure which contains all information // uiErr is a structure which contains all information
@ -30,7 +31,7 @@ type uiErr struct {
msg string msg string
detail string detail string
action string action string
help string hint string
} }
// Return the error message // Return the error message
@ -47,7 +48,7 @@ func (u uiErr) Msg(m string, args ...interface{}) uiErr {
msg: fmt.Sprintf(m, args...), msg: fmt.Sprintf(m, args...),
detail: u.detail, detail: u.detail,
action: u.action, action: u.action,
help: u.help, hint: u.hint,
} }
} }
@ -56,12 +57,12 @@ type uiErrFn func(err error) uiErr
// Create a UI error generator, this is needed to simplify // Create a UI error generator, this is needed to simplify
// the update of the detailed error message in several places // the update of the detailed error message in several places
// in MinIO code // in MinIO code
func newUIErrFn(msg, action, help string) uiErrFn { func newUIErrFn(msg, action, hint string) uiErrFn {
return func(err error) uiErr { return func(err error) uiErr {
u := uiErr{ u := uiErr{
msg: msg, msg: msg,
action: action, action: action,
help: help, hint: hint,
} }
if err != nil { if err != nil {
u.detail = err.Error() u.detail = err.Error()
@ -82,8 +83,13 @@ func errorToUIErr(err error) uiErr {
switch e := err.(type) { switch e := err.(type) {
case *net.OpError: case *net.OpError:
if e.Op == "listen" { if e.Op == "listen" {
return uiErrPortAlreadyInUse(e).Msg("Port " + e.Addr.String() + " is already in use") if oe, ok := e.Err.(*os.SyscallError); ok {
if oe.Err == syscall.EADDRINUSE {
return uiErrPortAlreadyInUse(e).Msg("Specified port '" + e.Addr.String() + "' is already in use")
} else if oe.Err == syscall.EACCES {
return uiErrPortAccess(e).Msg("Insufficient permissions to use specified port '" + e.Addr.String() + "'")
}
}
} }
case *os.PathError: case *os.PathError:
if os.IsPermission(e) { if os.IsPermission(e) {
@ -117,19 +123,19 @@ func fmtError(introMsg string, err error, jsonFlag bool) string {
// Pretty print error message // Pretty print error message
introMsg += ": " introMsg += ": "
if uiErr.msg != "" { if uiErr.msg != "" {
introMsg += colorBold(uiErr.msg + ".") introMsg += colorBold(uiErr.msg)
} else { } else {
introMsg += colorBold(err.Error() + ".") introMsg += colorBold(err.Error())
} }
renderedTxt += colorRed(introMsg) + "\n" renderedTxt += colorRed(introMsg) + "\n"
// Add action message // Add action message
if uiErr.action != "" { if uiErr.action != "" {
renderedTxt += "> " + colorBgYellow(colorBlack(uiErr.action+".")) + "\n" renderedTxt += "> " + colorBgYellow(colorBlack(uiErr.action)) + "\n"
} }
// Add help // Add hint
if uiErr.help != "" { if uiErr.hint != "" {
renderedTxt += colorBold("HELP:") + "\n" renderedTxt += colorBold("HINT:") + "\n"
renderedTxt += " " + uiErr.help renderedTxt += " " + uiErr.hint
} }
return renderedTxt return renderedTxt
} }

View File

@ -1,5 +1,5 @@
/* /*
* MinIO Cloud Storage, (C) 2018 MinIO, Inc. * MinIO Cloud Storage, (C) 2018-2019 MinIO, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -32,13 +32,13 @@ var (
uiErrInvalidDomainValue = newUIErrFn( uiErrInvalidDomainValue = newUIErrFn(
"Invalid domain value", "Invalid domain value",
"Please check the passed value", "Please check the passed value",
"Domain can only accept DNS compatible values.", "Domain can only accept DNS compatible values",
) )
uiErrInvalidErasureSetSize = newUIErrFn( uiErrInvalidErasureSetSize = newUIErrFn(
"Invalid erasure set size", "Invalid erasure set size",
"Please check the passed value", "Please check the passed value",
"Erasure set can only accept any of [4, 6, 8, 10, 12, 14, 16] values.", "Erasure set can only accept any of [4, 6, 8, 10, 12, 14, 16] values",
) )
uiErrInvalidWormValue = newUIErrFn( uiErrInvalidWormValue = newUIErrFn(
@ -62,32 +62,32 @@ var (
uiErrInvalidCacheExpiryValue = newUIErrFn( uiErrInvalidCacheExpiryValue = newUIErrFn(
"Invalid cache expiry value", "Invalid cache expiry value",
"Please check the passed value", "Please check the passed value",
"MINIO_CACHE_EXPIRY: Valid cache expiry duration is in days.", "MINIO_CACHE_EXPIRY: Valid cache expiry duration is in days",
) )
uiErrInvalidCacheMaxUse = newUIErrFn( uiErrInvalidCacheMaxUse = newUIErrFn(
"Invalid cache max-use value", "Invalid cache max-use value",
"Please check the passed value", "Please check the passed value",
"MINIO_CACHE_MAXUSE: Valid cache max-use value between 0-100.", "MINIO_CACHE_MAXUSE: Valid cache max-use value between 0-100",
) )
uiErrInvalidCredentials = newUIErrFn( uiErrInvalidCredentials = newUIErrFn(
"Invalid credentials", "Invalid credentials",
"Please provide correct credentials", "Please provide correct credentials",
`Access key length should be between minimum 3 characters in length. `Access key length should be between minimum 3 characters in length.
Secret key should be in between 8 and 40 characters.`, Secret key should be in between 8 and 40 characters`,
) )
uiErrEnvCredentialsMissingGateway = newUIErrFn( uiErrEnvCredentialsMissingGateway = newUIErrFn(
"Credentials missing", "Credentials missing",
"Please set your credentials in the environment", "Please set your credentials in the environment",
`In Gateway mode, access and secret keys should be specified via environment variables MINIO_ACCESS_KEY and MINIO_SECRET_KEY respectively.`, `In Gateway mode, access and secret keys should be specified via environment variables MINIO_ACCESS_KEY and MINIO_SECRET_KEY respectively`,
) )
uiErrEnvCredentialsMissingDistributed = newUIErrFn( uiErrEnvCredentialsMissingDistributed = newUIErrFn(
"Credentials missing", "Credentials missing",
"Please set your credentials in the environment", "Please set your credentials in the environment",
`In distributed server mode, access and secret keys should be specified via environment variables MINIO_ACCESS_KEY and MINIO_SECRET_KEY respectively.`, `In distributed server mode, access and secret keys should be specified via environment variables MINIO_ACCESS_KEY and MINIO_SECRET_KEY respectively`,
) )
uiErrInvalidErasureEndpoints = newUIErrFn( uiErrInvalidErasureEndpoints = newUIErrFn(
@ -105,9 +105,9 @@ Secret key should be in between 8 and 40 characters.`,
uiErrStorageClassValue = newUIErrFn( uiErrStorageClassValue = newUIErrFn(
"Invalid storage class value", "Invalid storage class value",
"Please check the value", "Please check the value",
`MINIO_STORAGE_CLASS_STANDARD: Format "EC:<Default_Parity_Standard_Class>" (e.g. "EC:3"). This sets the number of parity disks for MinIO server in Standard mode. Objects are stored in Standard mode, if storage class is not defined in Put request. `MINIO_STORAGE_CLASS_STANDARD: Format "EC:<Default_Parity_Standard_Class>" (e.g. "EC:3"). This sets the number of parity disks for MinIO server in Standard mode. Objects are stored in Standard mode, if storage class is not defined in Put request
MINIO_STORAGE_CLASS_RRS: Format "EC:<Default_Parity_Reduced_Redundancy_Class>" (e.g. "EC:3"). This sets the number of parity disks for MinIO server in Reduced Redundancy mode. Objects are stored in Reduced Redundancy mode, if Put request specifies RRS storage class. MINIO_STORAGE_CLASS_RRS: Format "EC:<Default_Parity_Reduced_Redundancy_Class>" (e.g. "EC:3"). This sets the number of parity disks for MinIO server in Reduced Redundancy mode. Objects are stored in Reduced Redundancy mode, if Put request specifies RRS storage class
Refer to the link https://github.com/minio/minio/tree/master/docs/erasure/storage-class for more information.`, Refer to the link https://github.com/minio/minio/tree/master/docs/erasure/storage-class for more information`,
) )
uiErrUnexpectedBackendVersion = newUIErrFn( uiErrUnexpectedBackendVersion = newUIErrFn(
@ -128,7 +128,7 @@ Refer to the link https://github.com/minio/minio/tree/master/docs/erasure/storag
uiErrInvalidFSEndpoint = newUIErrFn( uiErrInvalidFSEndpoint = newUIErrFn(
"Invalid endpoint for standalone FS mode", "Invalid endpoint for standalone FS mode",
"Please check the FS endpoint", "Please check the FS endpoint",
`FS mode requires only one writable disk path. `FS mode requires only one writable disk path
Example 1: Example 1:
$ minio server /data/minio/`, $ minio server /data/minio/`,
) )
@ -136,7 +136,7 @@ Example 1:
uiErrUnableToWriteInBackend = newUIErrFn( uiErrUnableToWriteInBackend = newUIErrFn(
"Unable to write to the backend", "Unable to write to the backend",
"Please ensure MinIO binary has write permissions for the backend", "Please ensure MinIO binary has write permissions for the backend",
"", `Verify if MinIO binary is running as the same user who has write permissions for the backend`,
) )
uiErrPortAlreadyInUse = newUIErrFn( uiErrPortAlreadyInUse = newUIErrFn(
@ -145,6 +145,12 @@ Example 1:
"", "",
) )
uiErrPortAccess = newUIErrFn(
"Unable to use specified port",
"Please ensure MinIO binary has 'cap_net_bind_service=+ep' permissions",
`Use 'sudo setcap cap_net_bind_service=+ep /path/to/minio' to provide sufficient permissions`,
)
uiErrNoPermissionsToAccessDirFiles = newUIErrFn( uiErrNoPermissionsToAccessDirFiles = newUIErrFn(
"Missing permissions to access the specified path", "Missing permissions to access the specified path",
"Please ensure the specified path can be accessed", "Please ensure the specified path can be accessed",
@ -154,7 +160,7 @@ Example 1:
uiErrSSLUnexpectedError = newUIErrFn( uiErrSSLUnexpectedError = newUIErrFn(
"Invalid TLS certificate", "Invalid TLS certificate",
"Please check the content of your certificate data", "Please check the content of your certificate data",
`Only PEM (x.509) format is accepted as valid public & private certificates.`, `Only PEM (x.509) format is accepted as valid public & private certificates`,
) )
uiErrSSLUnexpectedData = newUIErrFn( uiErrSSLUnexpectedData = newUIErrFn(
@ -171,8 +177,8 @@ Example 1:
uiErrNoCertsAndHTTPSEndpoints = newUIErrFn( uiErrNoCertsAndHTTPSEndpoints = newUIErrFn(
"HTTPS specified in endpoints, but no TLS certificate is found on the local machine", "HTTPS specified in endpoints, but no TLS certificate is found on the local machine",
"Please add a certificate or switch to HTTP.", "Please add TLS certificate or use HTTP endpoints only",
"Refer to https://docs.min.io/docs/how-to-secure-access-to-minio-server-with-tls for information about how to load a TLS certificate in your server.", "Refer to https://docs.min.io/docs/how-to-secure-access-to-minio-server-with-tls for information about how to load a TLS certificate in your server",
) )
uiErrCertsAndHTTPEndpoints = newUIErrFn( uiErrCertsAndHTTPEndpoints = newUIErrFn(