From bf8ec8ad73cc76bacf73c7bc110c1517e9058457 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Mon, 12 Aug 2019 21:25:34 -0700 Subject: [PATCH] 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 --- cmd/common-main.go | 3 +++ cmd/server-main.go | 4 ++-- cmd/signals.go | 16 ++++++++-------- cmd/ui-errors-utils.go | 34 ++++++++++++++++++++-------------- cmd/ui-errors.go | 38 ++++++++++++++++++++++---------------- 5 files changed, 55 insertions(+), 40 deletions(-) diff --git a/cmd/common-main.go b/cmd/common-main.go index 86baf12a5..9091e230f 100644 --- a/cmd/common-main.go +++ b/cmd/common-main.go @@ -61,6 +61,9 @@ func verifyObjectLayerFeatures(name string, objAPI ObjectLayer) { func checkUpdate(mode string) { // Its OK to ignore any errors during doUpdate() here. if updateMsg, _, currentReleaseTime, latestReleaseTime, err := getUpdateInfo(2*time.Second, mode); err == nil { + if updateMsg == "" { + return + } if globalInplaceUpdateDisabled { logger.StartupMessage(updateMsg) } else { diff --git a/cmd/server-main.go b/cmd/server-main.go index 881ad41a1..9728c8128 100644 --- a/cmd/server-main.go +++ b/cmd/server-main.go @@ -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"); * you may not use this file except in compliance with the License. @@ -377,7 +377,7 @@ func serverMain(ctx *cli.Context) { // Initialize notification system. 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 diff --git a/cmd/signals.go b/cmd/signals.go index c8475537d..0c9202003 100644 --- a/cmd/signals.go +++ b/cmd/signals.go @@ -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"); * you may not use this file except in compliance with the License. @@ -26,13 +26,13 @@ import ( func handleSignals() { // Custom exit function - exit := func(state bool) { + exit := func(success bool) { // If global profiler is set stop before we exit. if globalProfiler != nil { globalProfiler.Stop() } - if state { + if success { os.Exit(0) } @@ -66,13 +66,13 @@ func handleSignals() { for { select { case err := <-globalHTTPServerErrorCh: - logger.LogIf(context.Background(), err) - var oerr error if objAPI := newObjectLayerFn(); objAPI != nil { - oerr = objAPI.Shutdown(context.Background()) + objAPI.Shutdown(context.Background()) } - - exit(err == nil && oerr == nil) + if err != nil { + logger.Fatal(err, "Unable to start MinIO server") + } + exit(true) case osSignal := <-globalOSSignalCh: logger.Info("Exiting on signal: %s", strings.ToUpper(osSignal.String())) exit(stopProcess()) diff --git a/cmd/ui-errors-utils.go b/cmd/ui-errors-utils.go index f3a46e4b4..aea5c5779 100644 --- a/cmd/ui-errors-utils.go +++ b/cmd/ui-errors-utils.go @@ -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"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import ( "io" "net" "os" + "syscall" ) // uiErr is a structure which contains all information @@ -30,7 +31,7 @@ type uiErr struct { msg string detail string action string - help string + hint string } // Return the error message @@ -47,7 +48,7 @@ func (u uiErr) Msg(m string, args ...interface{}) uiErr { msg: fmt.Sprintf(m, args...), detail: u.detail, 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 // the update of the detailed error message in several places // in MinIO code -func newUIErrFn(msg, action, help string) uiErrFn { +func newUIErrFn(msg, action, hint string) uiErrFn { return func(err error) uiErr { u := uiErr{ msg: msg, action: action, - help: help, + hint: hint, } if err != nil { u.detail = err.Error() @@ -82,8 +83,13 @@ func errorToUIErr(err error) uiErr { switch e := err.(type) { case *net.OpError: 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: if os.IsPermission(e) { @@ -117,19 +123,19 @@ func fmtError(introMsg string, err error, jsonFlag bool) string { // Pretty print error message introMsg += ": " if uiErr.msg != "" { - introMsg += colorBold(uiErr.msg + ".") + introMsg += colorBold(uiErr.msg) } else { - introMsg += colorBold(err.Error() + ".") + introMsg += colorBold(err.Error()) } renderedTxt += colorRed(introMsg) + "\n" // Add action message if uiErr.action != "" { - renderedTxt += "> " + colorBgYellow(colorBlack(uiErr.action+".")) + "\n" + renderedTxt += "> " + colorBgYellow(colorBlack(uiErr.action)) + "\n" } - // Add help - if uiErr.help != "" { - renderedTxt += colorBold("HELP:") + "\n" - renderedTxt += " " + uiErr.help + // Add hint + if uiErr.hint != "" { + renderedTxt += colorBold("HINT:") + "\n" + renderedTxt += " " + uiErr.hint } return renderedTxt } diff --git a/cmd/ui-errors.go b/cmd/ui-errors.go index 87ec051c2..4758fbbfe 100644 --- a/cmd/ui-errors.go +++ b/cmd/ui-errors.go @@ -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"); * you may not use this file except in compliance with the License. @@ -32,13 +32,13 @@ var ( uiErrInvalidDomainValue = newUIErrFn( "Invalid domain value", "Please check the passed value", - "Domain can only accept DNS compatible values.", + "Domain can only accept DNS compatible values", ) uiErrInvalidErasureSetSize = newUIErrFn( "Invalid erasure set size", "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( @@ -62,32 +62,32 @@ var ( uiErrInvalidCacheExpiryValue = newUIErrFn( "Invalid cache expiry 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( "Invalid cache max-use 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( "Invalid credentials", "Please provide correct credentials", `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( "Credentials missing", "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( "Credentials missing", "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( @@ -105,9 +105,9 @@ Secret key should be in between 8 and 40 characters.`, uiErrStorageClassValue = newUIErrFn( "Invalid storage class value", "Please check the value", - `MINIO_STORAGE_CLASS_STANDARD: Format "EC:" (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:" (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.`, + `MINIO_STORAGE_CLASS_STANDARD: Format "EC:" (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:" (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`, ) uiErrUnexpectedBackendVersion = newUIErrFn( @@ -128,7 +128,7 @@ Refer to the link https://github.com/minio/minio/tree/master/docs/erasure/storag uiErrInvalidFSEndpoint = newUIErrFn( "Invalid endpoint for standalone FS mode", "Please check the FS endpoint", - `FS mode requires only one writable disk path. + `FS mode requires only one writable disk path Example 1: $ minio server /data/minio/`, ) @@ -136,7 +136,7 @@ Example 1: uiErrUnableToWriteInBackend = newUIErrFn( "Unable to write to 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( @@ -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( "Missing permissions to access the specified path", "Please ensure the specified path can be accessed", @@ -154,7 +160,7 @@ Example 1: uiErrSSLUnexpectedError = newUIErrFn( "Invalid TLS certificate", "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( @@ -171,8 +177,8 @@ Example 1: uiErrNoCertsAndHTTPSEndpoints = newUIErrFn( "HTTPS specified in endpoints, but no TLS certificate is found on the local machine", - "Please add a certificate or switch to HTTP.", - "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.", + "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", ) uiErrCertsAndHTTPEndpoints = newUIErrFn(