Handle errs returned with etcd properly for config init and migration (#7134)

Returning unexpected errors can cause problems for config handling,
which is what led gateway deployments with etcd to misbehave and
had stopped working properly
master
Harshavardhana 6 years ago committed by kannappanr
parent 55ef51a99d
commit ee7dcc2903
  1. 2
      cmd/admin-handlers_test.go
  2. 10
      cmd/admin-router.go
  3. 7
      cmd/config-migrate.go
  4. 25
      cmd/config.go
  5. 9
      cmd/gateway-main.go
  6. 2
      cmd/routers.go
  7. 5
      pkg/quick/encoding.go

@ -278,7 +278,7 @@ func prepareAdminXLTestBed() (*adminXLTestBed, error) {
// Setup admin mgmt REST API handlers. // Setup admin mgmt REST API handlers.
adminRouter := mux.NewRouter() adminRouter := mux.NewRouter()
registerAdminRouter(adminRouter, true) registerAdminRouter(adminRouter, true, true)
return &adminXLTestBed{ return &adminXLTestBed{
xlDirs: xlDirs, xlDirs: xlDirs,

@ -31,7 +31,7 @@ type adminAPIHandlers struct {
} }
// registerAdminRouter - Add handler functions for each service REST API routes. // registerAdminRouter - Add handler functions for each service REST API routes.
func registerAdminRouter(router *mux.Router, enableIAM bool) { func registerAdminRouter(router *mux.Router, enableConfigOps, enableIAMOps bool) {
adminAPI := adminAPIHandlers{} adminAPI := adminAPIHandlers{}
// Admin router // Admin router
@ -73,8 +73,7 @@ func registerAdminRouter(router *mux.Router, enableIAM bool) {
adminV1Router.Methods(http.MethodGet).Path("/profiling/download").HandlerFunc(httpTraceAll(adminAPI.DownloadProfilingHandler)) adminV1Router.Methods(http.MethodGet).Path("/profiling/download").HandlerFunc(httpTraceAll(adminAPI.DownloadProfilingHandler))
/// Config operations /// Config operations
if enableConfigOps {
if enableIAM {
// Update credentials // Update credentials
adminV1Router.Methods(http.MethodPut).Path("/config/credential").HandlerFunc(httpTraceHdrs(adminAPI.UpdateAdminCredentialsHandler)) adminV1Router.Methods(http.MethodPut).Path("/config/credential").HandlerFunc(httpTraceHdrs(adminAPI.UpdateAdminCredentialsHandler))
// Get config // Get config
@ -86,11 +85,14 @@ func registerAdminRouter(router *mux.Router, enableIAM bool) {
adminV1Router.Methods(http.MethodGet).Path("/config-keys").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigKeysHandler)) adminV1Router.Methods(http.MethodGet).Path("/config-keys").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigKeysHandler))
// Set config keys/values // Set config keys/values
adminV1Router.Methods(http.MethodPut).Path("/config-keys").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigKeysHandler)) adminV1Router.Methods(http.MethodPut).Path("/config-keys").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigKeysHandler))
}
if enableIAMOps {
// -- IAM APIs -- // -- IAM APIs --
// Add policy IAM // Add policy IAM
adminV1Router.Methods(http.MethodPut).Path("/add-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.AddCannedPolicy)).Queries("name", "{name:.*}") adminV1Router.Methods(http.MethodPut).Path("/add-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.AddCannedPolicy)).Queries("name",
"{name:.*}")
// Add user IAM // Add user IAM
adminV1Router.Methods(http.MethodPut).Path("/add-user").HandlerFunc(httpTraceHdrs(adminAPI.AddUser)).Queries("accessKey", "{accessKey:.*}") adminV1Router.Methods(http.MethodPut).Path("/add-user").HandlerFunc(httpTraceHdrs(adminAPI.AddUser)).Queries("accessKey", "{accessKey:.*}")

@ -27,7 +27,6 @@ import (
"github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/crypto"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/dns"
"github.com/minio/minio/pkg/event" "github.com/minio/minio/pkg/event"
"github.com/minio/minio/pkg/event/target" "github.com/minio/minio/pkg/event/target"
"github.com/minio/minio/pkg/iam/policy" "github.com/minio/minio/pkg/iam/policy"
@ -235,7 +234,7 @@ func purgeV1() error {
cv1 := &configV1{} cv1 := &configV1{}
_, err := Load(configFile, cv1) _, err := Load(configFile, cv1)
if os.IsNotExist(err) || err == dns.ErrNoEntriesFound { if os.IsNotExist(err) {
return nil return nil
} else if err != nil { } else if err != nil {
return fmt.Errorf("Unable to load config version ‘1’. %v", err) return fmt.Errorf("Unable to load config version ‘1’. %v", err)
@ -2454,10 +2453,14 @@ func migrateConfigToMinioSys(objAPI ObjectLayer) (err error) {
} }
// Read from deprecate file as well if necessary. // Read from deprecate file as well if necessary.
if _, err = Load(getConfigFile()+".deprecated", config); err != nil { if _, err = Load(getConfigFile()+".deprecated", config); err != nil {
if !os.IsNotExist(err) {
return err return err
} }
// If all else fails simply initialize the server config.
return newSrvConfig(objAPI)
} }
}
return saveServerConfig(context.Background(), objAPI, config) return saveServerConfig(context.Background(), objAPI, config)
} }

@ -20,7 +20,6 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"os"
"path" "path"
"runtime" "runtime"
"strings" "strings"
@ -160,16 +159,19 @@ func initConfig(objAPI ObjectLayer) error {
if globalEtcdClient != nil { if globalEtcdClient != nil {
if err := checkConfigEtcd(context.Background(), globalEtcdClient, getConfigFile()); err != nil { if err := checkConfigEtcd(context.Background(), globalEtcdClient, getConfigFile()); err != nil {
return err if err == errConfigNotFound {
}
// Migrates all configs at old location. // Migrates all configs at old location.
if err := migrateConfig(); err != nil { if err = migrateConfig(); err != nil {
return err return err
} }
// Migrates etcd ${HOME}/.minio/config.json to '/config/config.json' // Migrates etcd ${HOME}/.minio/config.json to '/config/config.json'
if err := migrateConfigToMinioSys(objAPI); err != nil { if err = migrateConfigToMinioSys(objAPI); err != nil {
return err return err
} }
} else {
return err
}
}
} else { } else {
if isFile(getConfigFile()) { if isFile(getConfigFile()) {
if err := migrateConfig(); err != nil { if err := migrateConfig(); err != nil {
@ -179,7 +181,7 @@ func initConfig(objAPI ObjectLayer) error {
// Migrates ${HOME}/.minio/config.json or config.json.deprecated // Migrates ${HOME}/.minio/config.json or config.json.deprecated
// to '<export_path>/.minio.sys/config/config.json' // to '<export_path>/.minio.sys/config/config.json'
// ignore if the file doesn't exist. // ignore if the file doesn't exist.
if err := migrateConfigToMinioSys(objAPI); err != nil && !os.IsNotExist(err) { if err := migrateConfigToMinioSys(objAPI); err != nil {
return err return err
} }
} }
@ -189,17 +191,6 @@ func initConfig(objAPI ObjectLayer) error {
// Watch config for changes and reloads them in-memory. // Watch config for changes and reloads them in-memory.
go watchConfig(objAPI, configFile, loadConfig) go watchConfig(objAPI, configFile, loadConfig)
if err := checkConfig(context.Background(), objAPI, configFile); err != nil {
if err == errConfigNotFound {
// Config file does not exist, we create it fresh and return upon success.
if err = newSrvConfig(objAPI); err != nil {
return err
}
} else {
return err
}
}
if err := migrateMinioSysConfig(objAPI); err != nil { if err := migrateMinioSysConfig(objAPI); err != nil {
return err return err
} }

@ -155,9 +155,12 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
registerSTSRouter(router) registerSTSRouter(router)
} }
enableConfigOps := globalEtcdClient != nil && gatewayName == "nas"
enableIAMOps := globalEtcdClient != nil
// Enable IAM admin APIs if etcd is enabled, if not just enable basic // Enable IAM admin APIs if etcd is enabled, if not just enable basic
// operations such as profiling, server info etc. // operations such as profiling, server info etc.
registerAdminRouter(router, globalEtcdClient != nil) registerAdminRouter(router, enableConfigOps, enableIAMOps)
// Add healthcheck router // Add healthcheck router
registerHealthCheckRouter(router) registerHealthCheckRouter(router)
@ -215,7 +218,7 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
logger.FatalIf(err, "Unable to initialize gateway backend") logger.FatalIf(err, "Unable to initialize gateway backend")
} }
if globalEtcdClient != nil && gatewayName == "nas" { if enableConfigOps {
// Create a new config system. // Create a new config system.
globalConfigSys = NewConfigSys() globalConfigSys = NewConfigSys()
@ -242,7 +245,7 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
// Create new IAM system. // Create new IAM system.
globalIAMSys = NewIAMSys() globalIAMSys = NewIAMSys()
if globalEtcdClient != nil { if enableIAMOps {
// Initialize IAM sys. // Initialize IAM sys.
_ = globalIAMSys.Init(newObject) _ = globalIAMSys.Init(newObject)
} }

@ -105,7 +105,7 @@ func configureServerHandler(endpoints EndpointList) (http.Handler, error) {
registerSTSRouter(router) registerSTSRouter(router)
// Add Admin router, all APIs are enabled in server mode. // Add Admin router, all APIs are enabled in server mode.
registerAdminRouter(router, true) registerAdminRouter(router, true, true)
// Add healthcheck router // Add healthcheck router
registerHealthCheckRouter(router) registerHealthCheckRouter(router)

@ -31,7 +31,6 @@ import (
"time" "time"
etcd "github.com/coreos/etcd/clientv3" etcd "github.com/coreos/etcd/clientv3"
dns "github.com/minio/minio/pkg/dns"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
@ -160,7 +159,7 @@ func loadFileConfigEtcd(filename string, clnt *etcd.Client, v interface{}) error
return fmt.Errorf("unexpected error %s returned by etcd setup, please check your endpoints %s", err, clnt.Endpoints()) return fmt.Errorf("unexpected error %s returned by etcd setup, please check your endpoints %s", err, clnt.Endpoints())
} }
if resp.Count == 0 { if resp.Count == 0 {
return dns.ErrNoEntriesFound return os.ErrNotExist
} }
for _, ev := range resp.Kvs { for _, ev := range resp.Kvs {
@ -173,7 +172,7 @@ func loadFileConfigEtcd(filename string, clnt *etcd.Client, v interface{}) error
return toUnmarshaller(filepath.Ext(filename))(fileData, v) return toUnmarshaller(filepath.Ext(filename))(fileData, v)
} }
} }
return dns.ErrNoEntriesFound return os.ErrNotExist
} }
// loadFileConfig unmarshals the file's content with the right // loadFileConfig unmarshals the file's content with the right

Loading…
Cancel
Save