diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index 2f249fcd1..228222743 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -530,12 +530,6 @@ func (a adminAPIHandlers) TopLocksHandler(w http.ResponseWriter, r *http.Request return } - // Method only allowed in Distributed XL mode. - if !globalIsDistXL { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - peerLocks := globalNotificationSys.GetLocks(ctx) // Once we have received all the locks currently used from peers // add the local peer locks list as well. diff --git a/cmd/admin-handlers_test.go b/cmd/admin-handlers_test.go index a4937c429..b1d7f372a 100644 --- a/cmd/admin-handlers_test.go +++ b/cmd/admin-handlers_test.go @@ -188,7 +188,7 @@ func testServiceSignalReceiver(cmd cmdType, t *testing.T) { func getServiceCmdRequest(cmd cmdType, cred auth.Credentials) (*http.Request, error) { queryVal := url.Values{} queryVal.Set("action", string(cmd.toServiceAction())) - resource := adminAPIPathPrefix + "/service?" + queryVal.Encode() + resource := adminPathPrefix + adminAPIVersionPrefix + "/service?" + queryVal.Encode() req, err := newTestRequest(http.MethodPost, resource, 0, nil) if err != nil { return nil, err @@ -257,7 +257,7 @@ func buildAdminRequest(queryVal url.Values, method, path string, contentLength int64, bodySeeker io.ReadSeeker) (*http.Request, error) { req, err := newTestRequest(method, - adminAPIPathPrefix+path+"?"+queryVal.Encode(), + adminPathPrefix+adminAPIVersionPrefix+path+"?"+queryVal.Encode(), contentLength, bodySeeker) if err != nil { return nil, err diff --git a/cmd/admin-router.go b/cmd/admin-router.go index 140eca3fa..973f0bbd7 100644 --- a/cmd/admin-router.go +++ b/cmd/admin-router.go @@ -24,138 +24,141 @@ import ( ) const ( - adminAPIPathPrefix = minioReservedBucketPath + "/admin/" + madmin.AdminAPIVersion + adminPathPrefix = minioReservedBucketPath + "/admin" + adminAPIVersion = madmin.AdminAPIVersion + adminAPIVersionPrefix = SlashSeparator + madmin.AdminAPIVersion ) // adminAPIHandlers provides HTTP handlers for MinIO admin API. -type adminAPIHandlers struct { -} +type adminAPIHandlers struct{} // registerAdminRouter - Add handler functions for each service REST API routes. func registerAdminRouter(router *mux.Router, enableConfigOps, enableIAMOps bool) { adminAPI := adminAPIHandlers{} // Admin router - adminRouter := router.PathPrefix(adminAPIPathPrefix).Subrouter() + adminRouter := router.PathPrefix(adminPathPrefix).Subrouter() /// Service operations // Restart and stop MinIO service. - adminRouter.Methods(http.MethodPost).Path("/service").HandlerFunc(httpTraceAll(adminAPI.ServiceActionHandler)).Queries("action", "{action:.*}") + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix+"/service").HandlerFunc(httpTraceAll(adminAPI.ServiceActionHandler)).Queries("action", "{action:.*}") // Update MinIO servers. - adminRouter.Methods(http.MethodPost).Path("/update").HandlerFunc(httpTraceAll(adminAPI.ServerUpdateHandler)).Queries("updateURL", "{updateURL:.*}") + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix+"/update").HandlerFunc(httpTraceAll(adminAPI.ServerUpdateHandler)).Queries("updateURL", "{updateURL:.*}") // Info operations - adminRouter.Methods(http.MethodGet).Path("/info").HandlerFunc(httpTraceAll(adminAPI.ServerInfoHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/info").HandlerFunc(httpTraceAll(adminAPI.ServerInfoHandler)) // Harware Info operations - adminRouter.Methods(http.MethodGet).Path("/hardware").HandlerFunc(httpTraceAll(adminAPI.ServerHardwareInfoHandler)).Queries("hwType", "{hwType:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/hardware").HandlerFunc(httpTraceAll(adminAPI.ServerHardwareInfoHandler)).Queries("hwType", "{hwType:.*}") // StorageInfo operations - adminRouter.Methods(http.MethodGet).Path("/storageinfo").HandlerFunc(httpTraceAll(adminAPI.StorageInfoHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/storageinfo").HandlerFunc(httpTraceAll(adminAPI.StorageInfoHandler)) if globalIsDistXL || globalIsXL { /// Heal operations // Heal processing endpoint. - adminRouter.Methods(http.MethodPost).Path("/heal/").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) - adminRouter.Methods(http.MethodPost).Path("/heal/{bucket}").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) - adminRouter.Methods(http.MethodPost).Path("/heal/{bucket}/{prefix:.*}").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix + "/heal/").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix + "/heal/{bucket}").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix + "/heal/{bucket}/{prefix:.*}").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) - adminRouter.Methods(http.MethodPost).Path("/background-heal/status").HandlerFunc(httpTraceAll(adminAPI.BackgroundHealStatusHandler)) + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix + "/background-heal/status").HandlerFunc(httpTraceAll(adminAPI.BackgroundHealStatusHandler)) /// Health operations } // Performance command - return performance details based on input type - adminRouter.Methods(http.MethodGet).Path("/performance").HandlerFunc(httpTraceAll(adminAPI.PerfInfoHandler)).Queries("perfType", "{perfType:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/performance").HandlerFunc(httpTraceAll(adminAPI.PerfInfoHandler)).Queries("perfType", "{perfType:.*}") // Profiling operations - adminRouter.Methods(http.MethodPost).Path("/profiling/start").HandlerFunc(httpTraceAll(adminAPI.StartProfilingHandler)). + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix+"/profiling/start").HandlerFunc(httpTraceAll(adminAPI.StartProfilingHandler)). Queries("profilerType", "{profilerType:.*}") - adminRouter.Methods(http.MethodGet).Path("/profiling/download").HandlerFunc(httpTraceAll(adminAPI.DownloadProfilingHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/profiling/download").HandlerFunc(httpTraceAll(adminAPI.DownloadProfilingHandler)) // Config KV operations. if enableConfigOps { - adminRouter.Methods(http.MethodGet).Path("/get-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigKVHandler)).Queries("key", "{key:.*}") - adminRouter.Methods(http.MethodPut).Path("/set-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigKVHandler)) - adminRouter.Methods(http.MethodDelete).Path("/del-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.DelConfigKVHandler)) - adminRouter.Methods(http.MethodGet).Path("/help-config-kv").HandlerFunc(httpTraceAll(adminAPI.HelpConfigKVHandler)).Queries("subSys", "{subSys:.*}", "key", "{key:.*}") - adminRouter.Methods(http.MethodGet).Path("/list-config-history-kv").HandlerFunc(httpTraceAll(adminAPI.ListConfigHistoryKVHandler)) - adminRouter.Methods(http.MethodDelete).Path("/clear-config-history-kv").HandlerFunc(httpTraceHdrs(adminAPI.ClearConfigHistoryKVHandler)).Queries("restoreId", "{restoreId:.*}") - adminRouter.Methods(http.MethodPut).Path("/restore-config-history-kv").HandlerFunc(httpTraceHdrs(adminAPI.RestoreConfigHistoryKVHandler)).Queries("restoreId", "{restoreId:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/get-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigKVHandler)).Queries("key", "{key:.*}") + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix + "/set-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigKVHandler)) + adminRouter.Methods(http.MethodDelete).Path(adminAPIVersionPrefix + "/del-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.DelConfigKVHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/help-config-kv").HandlerFunc(httpTraceAll(adminAPI.HelpConfigKVHandler)).Queries("subSys", "{subSys:.*}", "key", "{key:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/list-config-history-kv").HandlerFunc(httpTraceAll(adminAPI.ListConfigHistoryKVHandler)) + adminRouter.Methods(http.MethodDelete).Path(adminAPIVersionPrefix+"/clear-config-history-kv").HandlerFunc(httpTraceHdrs(adminAPI.ClearConfigHistoryKVHandler)).Queries("restoreId", "{restoreId:.*}") + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/restore-config-history-kv").HandlerFunc(httpTraceHdrs(adminAPI.RestoreConfigHistoryKVHandler)).Queries("restoreId", "{restoreId:.*}") } /// Config operations if enableConfigOps { // Get config - adminRouter.Methods(http.MethodGet).Path("/config").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/config").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigHandler)) // Set config - adminRouter.Methods(http.MethodPut).Path("/config").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigHandler)) + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix + "/config").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigHandler)) } if enableIAMOps { // -- IAM APIs -- // Add policy IAM - adminRouter.Methods(http.MethodPut).Path("/add-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.AddCannedPolicy)).Queries("name", + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/add-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.AddCannedPolicy)).Queries("name", "{name:.*}") // Add user IAM - adminRouter.Methods(http.MethodPut).Path("/add-user").HandlerFunc(httpTraceHdrs(adminAPI.AddUser)).Queries("accessKey", "{accessKey:.*}") - adminRouter.Methods(http.MethodPut).Path("/set-user-status").HandlerFunc(httpTraceHdrs(adminAPI.SetUserStatus)). + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/add-user").HandlerFunc(httpTraceHdrs(adminAPI.AddUser)).Queries("accessKey", "{accessKey:.*}") + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/set-user-status").HandlerFunc(httpTraceHdrs(adminAPI.SetUserStatus)). Queries("accessKey", "{accessKey:.*}").Queries("status", "{status:.*}") // Info policy IAM - adminRouter.Methods(http.MethodGet).Path("/info-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.InfoCannedPolicy)).Queries("name", "{name:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/info-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.InfoCannedPolicy)).Queries("name", "{name:.*}") // Remove policy IAM - adminRouter.Methods(http.MethodDelete).Path("/remove-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.RemoveCannedPolicy)).Queries("name", "{name:.*}") + adminRouter.Methods(http.MethodDelete).Path(adminAPIVersionPrefix+"/remove-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.RemoveCannedPolicy)).Queries("name", "{name:.*}") // Set user or group policy - adminRouter.Methods(http.MethodPut).Path("/set-user-or-group-policy"). + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/set-user-or-group-policy"). HandlerFunc(httpTraceHdrs(adminAPI.SetPolicyForUserOrGroup)). Queries("policyName", "{policyName:.*}", "userOrGroup", "{userOrGroup:.*}", "isGroup", "{isGroup:true|false}") // Remove user IAM - adminRouter.Methods(http.MethodDelete).Path("/remove-user").HandlerFunc(httpTraceHdrs(adminAPI.RemoveUser)).Queries("accessKey", "{accessKey:.*}") + adminRouter.Methods(http.MethodDelete).Path(adminAPIVersionPrefix+"/remove-user").HandlerFunc(httpTraceHdrs(adminAPI.RemoveUser)).Queries("accessKey", "{accessKey:.*}") // List users - adminRouter.Methods(http.MethodGet).Path("/list-users").HandlerFunc(httpTraceHdrs(adminAPI.ListUsers)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/list-users").HandlerFunc(httpTraceHdrs(adminAPI.ListUsers)) // User info - adminRouter.Methods(http.MethodGet).Path("/user-info").HandlerFunc(httpTraceHdrs(adminAPI.GetUserInfo)).Queries("accessKey", "{accessKey:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/user-info").HandlerFunc(httpTraceHdrs(adminAPI.GetUserInfo)).Queries("accessKey", "{accessKey:.*}") // Add/Remove members from group - adminRouter.Methods(http.MethodPut).Path("/update-group-members").HandlerFunc(httpTraceHdrs(adminAPI.UpdateGroupMembers)) + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix + "/update-group-members").HandlerFunc(httpTraceHdrs(adminAPI.UpdateGroupMembers)) // Get Group - adminRouter.Methods(http.MethodGet).Path("/group").HandlerFunc(httpTraceHdrs(adminAPI.GetGroup)).Queries("group", "{group:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/group").HandlerFunc(httpTraceHdrs(adminAPI.GetGroup)).Queries("group", "{group:.*}") // List Groups - adminRouter.Methods(http.MethodGet).Path("/groups").HandlerFunc(httpTraceHdrs(adminAPI.ListGroups)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/groups").HandlerFunc(httpTraceHdrs(adminAPI.ListGroups)) // Set Group Status - adminRouter.Methods(http.MethodPut).Path("/set-group-status").HandlerFunc(httpTraceHdrs(adminAPI.SetGroupStatus)).Queries("group", "{group:.*}").Queries("status", "{status:.*}") + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/set-group-status").HandlerFunc(httpTraceHdrs(adminAPI.SetGroupStatus)).Queries("group", "{group:.*}").Queries("status", "{status:.*}") // List policies - adminRouter.Methods(http.MethodGet).Path("/list-canned-policies").HandlerFunc(httpTraceHdrs(adminAPI.ListCannedPolicies)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/list-canned-policies").HandlerFunc(httpTraceHdrs(adminAPI.ListCannedPolicies)) } // -- Top APIs -- // Top locks - adminRouter.Methods(http.MethodGet).Path("/top/locks").HandlerFunc(httpTraceHdrs(adminAPI.TopLocksHandler)) + if globalIsDistXL { + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/top/locks").HandlerFunc(httpTraceHdrs(adminAPI.TopLocksHandler)) + } // HTTP Trace - adminRouter.Methods(http.MethodGet).Path("/trace").HandlerFunc(adminAPI.TraceHandler) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/trace").HandlerFunc(adminAPI.TraceHandler) // Console Logs - adminRouter.Methods(http.MethodGet).Path("/log").HandlerFunc(httpTraceAll(adminAPI.ConsoleLogHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/log").HandlerFunc(httpTraceAll(adminAPI.ConsoleLogHandler)) // -- KMS APIs -- // - adminRouter.Methods(http.MethodGet).Path("/kms/key/status").HandlerFunc(httpTraceAll(adminAPI.KMSKeyStatusHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/kms/key/status").HandlerFunc(httpTraceAll(adminAPI.KMSKeyStatusHandler)) - // If none of the routes match, return error. - adminRouter.NotFoundHandler = http.HandlerFunc(httpTraceHdrs(notFoundHandler)) - adminRouter.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(versionMismatchHandler)) + // If none of the routes match add default error handler routes + adminRouter.NotFoundHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) + adminRouter.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) } diff --git a/cmd/api-errors.go b/cmd/api-errors.go index 9d650a568..652ec359a 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -141,7 +141,6 @@ const ( ErrInvalidPrefixMarker ErrBadRequest ErrKeyTooLongError - ErrInvalidAPIVersion // Add new error codes here. // SSE-S3 related API errors @@ -1503,11 +1502,6 @@ var errorCodes = errorCodeMap{ Description: "Invalid according to Policy: Policy Condition failed", HTTPStatusCode: http.StatusForbidden, }, - ErrInvalidAPIVersion: { - Code: "ErrInvalidAPIVersion", - Description: "Invalid version found in the request", - HTTPStatusCode: http.StatusNotFound, - }, // Add your error structure here. } diff --git a/cmd/api-response.go b/cmd/api-response.go index d17ec0e62..7000c9bd9 100644 --- a/cmd/api-response.go +++ b/cmd/api-response.go @@ -694,6 +694,11 @@ func writeErrorResponseHeadersOnly(w http.ResponseWriter, err APIError) { writeResponse(w, err.HTTPStatusCode, nil, mimeNone) } +func writeErrorResponseString(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) { + // Generate string error response. + writeResponse(w, err.HTTPStatusCode, []byte(err.Description), mimeNone) +} + // writeErrorResponseJSON - writes error response in JSON format; // useful for admin APIs. func writeErrorResponseJSON(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) { diff --git a/cmd/api-router.go b/cmd/api-router.go index c1b0f38ce..541c242bc 100644 --- a/cmd/api-router.go +++ b/cmd/api-router.go @@ -171,6 +171,8 @@ func registerAPIRouter(router *mux.Router, encryptionEnabled, allowSSEKMS bool) // ListBuckets apiRouter.Methods(http.MethodGet).Path(SlashSeparator).HandlerFunc(collectAPIStats("listbuckets", httpTraceAll(api.ListBucketsHandler))) - // If none of the routes match. - apiRouter.NotFoundHandler = http.HandlerFunc(collectAPIStats("notfound", httpTraceAll(notFoundHandler))) + // If none of the routes match add default error handler routes + apiRouter.NotFoundHandler = http.HandlerFunc(collectAPIStats("notfound", httpTraceAll(errorResponseHandler))) + apiRouter.MethodNotAllowedHandler = http.HandlerFunc(collectAPIStats("methodnotallowed", httpTraceAll(errorResponseHandler))) + } diff --git a/cmd/config-encrypted.go b/cmd/config-encrypted.go index 98c4ec4df..f3a4a1e93 100644 --- a/cmd/config-encrypted.go +++ b/cmd/config-encrypted.go @@ -41,6 +41,20 @@ func handleEncryptedConfigBackend(objAPI ObjectLayer, server bool) error { var encrypted bool var err error + // Construct path to config/transaction.lock for locking + transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" + + // Make sure to hold lock for entire migration to avoid + // such that only one server should migrate the entire config + // at a given time, this big transaction lock ensures this + // appropriately. This is also true for rotation of encrypted + // content. + objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) + if err := objLock.GetLock(globalOperationTimeout); err != nil { + return err + } + defer objLock.Unlock() + // Migrating Config backend needs a retry mechanism for // the following reasons: // - Read quorum is lost just after the initialization @@ -48,8 +62,7 @@ func handleEncryptedConfigBackend(objAPI ObjectLayer, server bool) error { for range newRetryTimerSimple(doneCh) { if encrypted, err = checkBackendEncrypted(objAPI); err != nil { if err == errDiskNotFound || - strings.Contains(err.Error(), InsufficientReadQuorum{}.Error()) || - strings.Contains(err.Error(), InsufficientWriteQuorum{}.Error()) { + strings.Contains(err.Error(), InsufficientReadQuorum{}.Error()) { logger.Info("Waiting for config backend to be encrypted..") continue } @@ -247,18 +260,6 @@ func migrateConfigPrefixToEncrypted(objAPI ObjectLayer, activeCredOld auth.Crede logger.Info("Attempting a rotation of encrypted config, IAM users and policies on MinIO with newly supplied credentials") } - // Construct path to config/transaction.lock for locking - transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" - - // As object layer's GetObject() and PutObject() take respective lock on minioMetaBucket - // and configFile, take a transaction lock to avoid data race between readConfig() - // and saveConfig(). - objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) - if err := objLock.GetLock(globalOperationTimeout); err != nil { - return err - } - defer objLock.Unlock() - var marker string for { res, err := objAPI.ListObjects(context.Background(), minioMetaBucket, minioConfigPrefix, marker, "", maxObjectList) diff --git a/cmd/config-migrate.go b/cmd/config-migrate.go index 599be3657..173d354ff 100644 --- a/cmd/config-migrate.go +++ b/cmd/config-migrate.go @@ -2427,11 +2427,6 @@ func migrateConfigToMinioSys(objAPI ObjectLayer) (err error) { // Construct path to config.json for the given bucket. configFile := path.Join(minioConfigPrefix, minioConfigFile) - // Verify if config was already available in .minio.sys in which case, nothing more to be done. - if err = checkConfig(context.Background(), objAPI, configFile); err != errConfigNotFound { - return err - } - defer func() { if err == nil { if globalEtcdClient != nil { @@ -2444,18 +2439,6 @@ func migrateConfigToMinioSys(objAPI ObjectLayer) (err error) { } }() - // Construct path to config/transaction.lock for locking - transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" - - // As object layer's GetObject() and PutObject() take respective lock on minioMetaBucket - // and configFile, take a transaction lock to avoid data race between readConfig() - // and saveConfig(). - objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) - if err = objLock.GetLock(globalOperationTimeout); err != nil { - return err - } - defer objLock.Unlock() - // Verify if backend already has the file (after holding lock) if err = checkConfig(context.Background(), objAPI, configFile); err != errConfigNotFound { return err @@ -2488,6 +2471,7 @@ func migrateConfigToMinioSys(objAPI ObjectLayer) (err error) { // Migrates '.minio.sys/config.json' to v33. func migrateMinioSysConfig(objAPI ObjectLayer) error { + // Construct path to config.json for the given bucket. configFile := path.Join(minioConfigPrefix, minioConfigFile) // Check if the config version is latest, if not migrate. @@ -2499,18 +2483,6 @@ func migrateMinioSysConfig(objAPI ObjectLayer) error { return nil } - // Construct path to config/transaction.lock for locking - transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" - - // As object layer's GetObject() and PutObject() take respective lock on minioMetaBucket - // and configFile, take a transaction lock to avoid data race between readConfig() - // and saveConfig(). - objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) - if err := objLock.GetLock(globalOperationTimeout); err != nil { - return err - } - defer objLock.Unlock() - if err := migrateV27ToV28MinioSys(objAPI); err != nil { return err } @@ -2806,18 +2778,6 @@ func migrateMinioSysConfigToKV(objAPI ObjectLayer) error { notify.SetNotifyWebhook(newCfg, k, args) } - // Construct path to config/transaction.lock for locking - transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" - - // As object layer's GetObject() and PutObject() take respective lock on minioMetaBucket - // and configFile, take a transaction lock to avoid data race between readConfig() - // and saveConfig(). - objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) - if err = objLock.GetLock(globalOperationTimeout); err != nil { - return err - } - defer objLock.Unlock() - if err = saveServerConfig(context.Background(), objAPI, newCfg, cfg); err != nil { return err } diff --git a/cmd/config.go b/cmd/config.go index 1223fb115..2d1d93bad 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -233,7 +233,8 @@ func (sys *ConfigSys) Init(objAPI ObjectLayer) error { select { case <-retryTimerCh: if err := initConfig(objAPI); err != nil { - if strings.Contains(err.Error(), InsufficientReadQuorum{}.Error()) || + if err == errDiskNotFound || + strings.Contains(err.Error(), InsufficientReadQuorum{}.Error()) || strings.Contains(err.Error(), InsufficientWriteQuorum{}.Error()) { logger.Info("Waiting for configuration to be initialized..") continue @@ -264,6 +265,19 @@ func initConfig(objAPI ObjectLayer) error { } } + // Construct path to config/transaction.lock for locking + transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" + + // Hold lock only by one server and let that server alone migrate + // all the config as necessary, this is to ensure that + // redundant locks are not held for each migration - this allows + // for a more predictable behavior while debugging. + objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) + if err := objLock.GetLock(globalOperationTimeout); err != nil { + return err + } + defer objLock.Unlock() + // Migrates ${HOME}/.minio/config.json or config.json.deprecated // to '/.minio.sys/config/config.json' // ignore if the file doesn't exist. diff --git a/cmd/format-disk-cache_test.go b/cmd/format-disk-cache_test.go index d818f0277..9e64674e4 100644 --- a/cmd/format-disk-cache_test.go +++ b/cmd/format-disk-cache_test.go @@ -36,7 +36,7 @@ func TestDiskCacheFormat(t *testing.T) { } // Do the basic sanity checks to check if initFormatCache() did its job. cacheFormatPath := pathJoin(fsDirs[0], minioMetaBucket, formatConfigFile) - f, err := os.OpenFile(cacheFormatPath, os.O_RDWR, 0) + f, err := os.OpenFile(cacheFormatPath, os.O_RDWR|os.O_SYNC, 0) if err != nil { t.Fatal(err) } diff --git a/cmd/format-fs_test.go b/cmd/format-fs_test.go index 9e657a92c..dc9f187d9 100644 --- a/cmd/format-fs_test.go +++ b/cmd/format-fs_test.go @@ -46,7 +46,7 @@ func TestFSFormatFS(t *testing.T) { rlk.Close() // Do the basic sanity checks to check if initFormatFS() did its job. - f, err := os.OpenFile(fsFormatPath, os.O_RDWR, 0) + f, err := os.OpenFile(fsFormatPath, os.O_RDWR|os.O_SYNC, 0) if err != nil { t.Fatal(err) } diff --git a/cmd/gateway-router.go b/cmd/gateway-interface.go similarity index 100% rename from cmd/gateway-router.go rename to cmd/gateway-interface.go diff --git a/cmd/generic-handlers.go b/cmd/generic-handlers.go index 9f2e7d9c9..1e0dd6141 100644 --- a/cmd/generic-handlers.go +++ b/cmd/generic-handlers.go @@ -276,7 +276,7 @@ func (h cacheControlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Check to allow access to the reserved "bucket" `/minio` for Admin // API requests. func isAdminReq(r *http.Request) bool { - return strings.HasPrefix(r.URL.Path, adminAPIPathPrefix+SlashSeparator) + return strings.HasPrefix(r.URL.Path, adminPathPrefix) } // Adds verification for incoming paths. @@ -293,11 +293,11 @@ func (h minioReservedBucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Req case guessIsRPCReq(r), guessIsBrowserReq(r), guessIsHealthCheckReq(r), guessIsMetricsReq(r), isAdminReq(r): // Allow access to reserved buckets default: - // For all other requests reject access to reserved - // buckets + // For all other requests reject access to reserved buckets bucketName, _ := request2BucketObjectName(r) if isMinioReservedBucket(bucketName) || isMinioMetaBucket(bucketName) { - writeErrorResponse(context.Background(), w, errorCodes.ToAPIErr(ErrAllAccessDisabled), r.URL, guessIsBrowserReq(r)) + browser := guessIsBrowserReq(r) + writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrAllAccessDisabled), r.URL, browser) return } } diff --git a/cmd/handler-utils.go b/cmd/handler-utils.go index a43cb2bd7..1a12dfbe5 100644 --- a/cmd/handler-utils.go +++ b/cmd/handler-utils.go @@ -19,18 +19,21 @@ package cmd import ( "bytes" "context" + "fmt" "io" "io/ioutil" "mime/multipart" "net" "net/http" "net/url" + "regexp" "strings" xhttp "github.com/minio/minio/cmd/http" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/handlers" + "github.com/minio/minio/pkg/madmin" ) // Parses location constraint from the incoming reader. @@ -408,23 +411,61 @@ func getResource(path string, host string, domains []string) (string, error) { return path, nil } -// If none of the http routes match respond with MethodNotAllowed -func notFoundHandler(w http.ResponseWriter, r *http.Request) { - writeErrorResponse(context.Background(), w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) +var regexVersion = regexp.MustCompile(`(\w\d+)`) + +func extractAPIVersion(r *http.Request) string { + return regexVersion.FindString(r.URL.Path) } -// If the API version does not match with current version. -func versionMismatchHandler(w http.ResponseWriter, r *http.Request) { - path := r.URL.Path +// If none of the http routes match respond with appropriate errors +func errorResponseHandler(w http.ResponseWriter, r *http.Request) { + version := extractAPIVersion(r) switch { - case strings.HasPrefix(path, minioReservedBucketPath+"/peer/"): - writeVersionMismatchResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidAPIVersion), r.URL, false) - case strings.HasPrefix(path, minioReservedBucketPath+"/storage/"): - writeVersionMismatchResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidAPIVersion), r.URL, false) - case strings.HasPrefix(path, minioReservedBucketPath+"/lock/"): - writeVersionMismatchResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidAPIVersion), r.URL, false) + case strings.HasPrefix(r.URL.Path, peerRESTPrefix): + desc := fmt.Sprintf("Expected 'peer' API version '%s', instead found '%s', please upgrade the servers", + peerRESTVersion, version) + writeErrorResponseString(r.Context(), w, APIError{ + Code: "XMinioPeerVersionMismatch", + Description: desc, + HTTPStatusCode: http.StatusBadRequest, + }, r.URL) + case strings.HasPrefix(r.URL.Path, storageRESTPrefix): + desc := fmt.Sprintf("Expected 'storage' API version '%s', instead found '%s', please upgrade the servers", + storageRESTVersion, version) + writeErrorResponseString(r.Context(), w, APIError{ + Code: "XMinioStorageVersionMismatch", + Description: desc, + HTTPStatusCode: http.StatusBadRequest, + }, r.URL) + case strings.HasPrefix(r.URL.Path, lockRESTPrefix): + desc := fmt.Sprintf("Expected 'lock' API version '%s', instead found '%s', please upgrade the servers", + lockRESTVersion, version) + writeErrorResponseString(r.Context(), w, APIError{ + Code: "XMinioLockVersionMismatch", + Description: desc, + HTTPStatusCode: http.StatusBadRequest, + }, r.URL) + case strings.HasPrefix(r.URL.Path, adminPathPrefix): + var desc string + if version == "v1" { + desc = fmt.Sprintf("Server expects client requests with 'admin' API version '%s', found '%s', please upgrade the client to latest releases", madmin.AdminAPIVersion, version) + } else if version == madmin.AdminAPIVersion { + desc = fmt.Sprintf("This 'admin' API is not supported by server in '%s'", getMinioMode()) + } else { + desc = fmt.Sprintf("Unexpected client 'admin' API version found '%s', expected '%s', please downgrade the client to older releases", version, madmin.AdminAPIVersion) + } + writeErrorResponseJSON(r.Context(), w, APIError{ + Code: "XMinioAdminVersionMismatch", + Description: desc, + HTTPStatusCode: http.StatusBadRequest, + }, r.URL) default: - writeVersionMismatchResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidAPIVersion), r.URL, true) + desc := fmt.Sprintf("Unknown API request at %s", r.URL.Path) + writeErrorResponse(r.Context(), w, APIError{ + Code: "XMinioUnknownAPIRequest", + Description: desc, + HTTPStatusCode: http.StatusBadRequest, + }, r.URL, guessIsBrowserReq(r)) } } diff --git a/cmd/lock-rest-server-common.go b/cmd/lock-rest-server-common.go index 7efeec7b2..74961cb9a 100644 --- a/cmd/lock-rest-server-common.go +++ b/cmd/lock-rest-server-common.go @@ -18,22 +18,23 @@ package cmd import ( "errors" - "path" "time" ) -const lockRESTVersion = "v2" -const lockRESTPath = minioReservedBucketPath + "/lock/" + lockRESTVersion - -var lockServicePath = path.Join(minioReservedBucketPath, lockServiceSubPath) +const ( + lockRESTVersion = "v2" + lockRESTVersionPrefix = SlashSeparator + "v2" + lockRESTPrefix = minioReservedBucketPath + "/lock" + lockRESTPath = lockRESTPrefix + lockRESTVersionPrefix +) const ( - lockRESTMethodLock = "lock" - lockRESTMethodRLock = "rlock" - lockRESTMethodUnlock = "unlock" - lockRESTMethodRUnlock = "runlock" - lockRESTMethodForceUnlock = "forceunlock" - lockRESTMethodExpired = "expired" + lockRESTMethodLock = "/lock" + lockRESTMethodRLock = "/rlock" + lockRESTMethodUnlock = "/unlock" + lockRESTMethodRUnlock = "/runlock" + lockRESTMethodForceUnlock = "/forceunlock" + lockRESTMethodExpired = "/expired" // Unique ID of lock/unlock request. lockRESTUID = "uid" diff --git a/cmd/lock-rest-server.go b/cmd/lock-rest-server.go index 53bd14805..ca1b1db52 100644 --- a/cmd/lock-rest-server.go +++ b/cmd/lock-rest-server.go @@ -30,9 +30,6 @@ import ( ) const ( - // Lock rpc server endpoint. - lockServiceSubPath = "/lock" - // Lock maintenance interval. lockMaintenanceInterval = 1 * time.Minute @@ -246,16 +243,18 @@ func startLockMaintenance(lkSrv *lockRESTServer) { // registerLockRESTHandlers - register lock rest router. func registerLockRESTHandlers(router *mux.Router) { - subrouter := router.PathPrefix(lockRESTPath).Subrouter() + subrouter := router.PathPrefix(lockRESTPrefix).Subrouter() queries := restQueries(lockRESTUID, lockRESTSource, lockRESTResource, lockRESTServerAddr, lockRESTServerEndpoint) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodLock).HandlerFunc(httpTraceHdrs(globalLockServer.LockHandler)).Queries(queries...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodRLock).HandlerFunc(httpTraceHdrs(globalLockServer.RLockHandler)).Queries(queries...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.UnlockHandler)).Queries(queries...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodRUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.RUnlockHandler)).Queries(queries...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodForceUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.ForceUnlockHandler)).Queries(queries...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodExpired).HandlerFunc(httpTraceAll(globalLockServer.ExpiredHandler)).Queries(queries...) - - router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(versionMismatchHandler)) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodLock).HandlerFunc(httpTraceHdrs(globalLockServer.LockHandler)).Queries(queries...) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodRLock).HandlerFunc(httpTraceHdrs(globalLockServer.RLockHandler)).Queries(queries...) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.UnlockHandler)).Queries(queries...) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodRUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.RUnlockHandler)).Queries(queries...) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodForceUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.ForceUnlockHandler)).Queries(queries...) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodExpired).HandlerFunc(httpTraceAll(globalLockServer.ExpiredHandler)).Queries(queries...) + + // If none of the routes match add default error handler routes + router.NotFoundHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) + router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) // Start lock maintenance from all lock servers. go startLockMaintenance(globalLockServer) diff --git a/cmd/namespace-lock.go b/cmd/namespace-lock.go index f848ff664..cd1ead334 100644 --- a/cmd/namespace-lock.go +++ b/cmd/namespace-lock.go @@ -70,7 +70,7 @@ func newDsyncNodes(endpoints EndpointList) (clnts []dsync.NetLocker, myNode int, globalLockServer = &lockRESTServer{ ll: &localLocker{ serverAddr: endpoint.Host, - serviceEndpoint: lockServicePath, + serviceEndpoint: lockRESTPrefix, lockMap: make(map[string][]lockRequesterInfo), }, } diff --git a/cmd/peer-rest-common.go b/cmd/peer-rest-common.go index 8aacae4fb..ac4a8fe87 100644 --- a/cmd/peer-rest-common.go +++ b/cmd/peer-rest-common.go @@ -16,44 +16,48 @@ package cmd -const peerRESTVersion = "v6" -const peerRESTPath = minioReservedBucketPath + "/peer/" + peerRESTVersion +const ( + peerRESTVersion = "v6" + peerRESTVersionPrefix = SlashSeparator + peerRESTVersion + peerRESTPrefix = minioReservedBucketPath + "/peer" + peerRESTPath = peerRESTPrefix + peerRESTVersionPrefix +) const ( - peerRESTMethodNetReadPerfInfo = "netreadperfinfo" - peerRESTMethodCollectNetPerfInfo = "collectnetperfinfo" - peerRESTMethodServerInfo = "serverinfo" - peerRESTMethodCPULoadInfo = "cpuloadinfo" - peerRESTMethodMemUsageInfo = "memusageinfo" - peerRESTMethodDrivePerfInfo = "driveperfinfo" - peerRESTMethodDeleteBucket = "deletebucket" - peerRESTMethodServerUpdate = "serverupdate" - peerRESTMethodSignalService = "signalservice" - peerRESTMethodBackgroundHealStatus = "backgroundhealstatus" - peerRESTMethodBackgroundOpsStatus = "backgroundopsstatus" - peerRESTMethodGetLocks = "getlocks" - peerRESTMethodBucketPolicyRemove = "removebucketpolicy" - peerRESTMethodLoadUser = "loaduser" - peerRESTMethodDeleteUser = "deleteuser" - peerRESTMethodLoadPolicy = "loadpolicy" - peerRESTMethodLoadPolicyMapping = "loadpolicymapping" - peerRESTMethodDeletePolicy = "deletepolicy" - peerRESTMethodLoadUsers = "loadusers" - peerRESTMethodLoadGroup = "loadgroup" - peerRESTMethodStartProfiling = "startprofiling" - peerRESTMethodDownloadProfilingData = "downloadprofilingdata" - peerRESTMethodBucketPolicySet = "setbucketpolicy" - peerRESTMethodBucketNotificationPut = "putbucketnotification" - peerRESTMethodBucketNotificationListen = "listenbucketnotification" - peerRESTMethodReloadFormat = "reloadformat" - peerRESTMethodTargetExists = "targetexists" - peerRESTMethodSendEvent = "sendevent" - peerRESTMethodTrace = "trace" - peerRESTMethodBucketLifecycleSet = "setbucketlifecycle" - peerRESTMethodBucketLifecycleRemove = "removebucketlifecycle" - peerRESTMethodLog = "log" - peerRESTMethodHardwareCPUInfo = "cpuhardwareinfo" - peerRESTMethodHardwareNetworkInfo = "networkhardwareinfo" + peerRESTMethodNetReadPerfInfo = "/netreadperfinfo" + peerRESTMethodCollectNetPerfInfo = "/collectnetperfinfo" + peerRESTMethodServerInfo = "/serverinfo" + peerRESTMethodCPULoadInfo = "/cpuloadinfo" + peerRESTMethodMemUsageInfo = "/memusageinfo" + peerRESTMethodDrivePerfInfo = "/driveperfinfo" + peerRESTMethodDeleteBucket = "/deletebucket" + peerRESTMethodServerUpdate = "/serverupdate" + peerRESTMethodSignalService = "/signalservice" + peerRESTMethodBackgroundHealStatus = "/backgroundhealstatus" + peerRESTMethodBackgroundOpsStatus = "/backgroundopsstatus" + peerRESTMethodGetLocks = "/getlocks" + peerRESTMethodBucketPolicyRemove = "/removebucketpolicy" + peerRESTMethodLoadUser = "/loaduser" + peerRESTMethodDeleteUser = "/deleteuser" + peerRESTMethodLoadPolicy = "/loadpolicy" + peerRESTMethodLoadPolicyMapping = "/loadpolicymapping" + peerRESTMethodDeletePolicy = "/deletepolicy" + peerRESTMethodLoadUsers = "/loadusers" + peerRESTMethodLoadGroup = "/loadgroup" + peerRESTMethodStartProfiling = "/startprofiling" + peerRESTMethodDownloadProfilingData = "/downloadprofilingdata" + peerRESTMethodBucketPolicySet = "/setbucketpolicy" + peerRESTMethodBucketNotificationPut = "/putbucketnotification" + peerRESTMethodBucketNotificationListen = "/listenbucketnotification" + peerRESTMethodReloadFormat = "/reloadformat" + peerRESTMethodTargetExists = "/targetexists" + peerRESTMethodSendEvent = "/sendevent" + peerRESTMethodTrace = "/trace" + peerRESTMethodBucketLifecycleSet = "/setbucketlifecycle" + peerRESTMethodBucketLifecycleRemove = "/removebucketlifecycle" + peerRESTMethodLog = "/log" + peerRESTMethodHardwareCPUInfo = "/cpuhardwareinfo" + peerRESTMethodHardwareNetworkInfo = "/networkhardwareinfo" ) const ( diff --git a/cmd/peer-rest-server.go b/cmd/peer-rest-server.go index 285330154..5d0981951 100644 --- a/cmd/peer-rest-server.go +++ b/cmd/peer-rest-server.go @@ -995,47 +995,49 @@ func (s *peerRESTServer) IsValid(w http.ResponseWriter, r *http.Request) bool { // registerPeerRESTHandlers - register peer rest router. func registerPeerRESTHandlers(router *mux.Router) { server := &peerRESTServer{} - subrouter := router.PathPrefix(peerRESTPath).Subrouter() - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodNetReadPerfInfo).HandlerFunc(httpTraceHdrs(server.NetReadPerfInfoHandler)).Queries(restQueries(peerRESTNetPerfSize)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodCollectNetPerfInfo).HandlerFunc(httpTraceHdrs(server.CollectNetPerfInfoHandler)).Queries(restQueries(peerRESTNetPerfSize)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodGetLocks).HandlerFunc(httpTraceHdrs(server.GetLocksHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodServerInfo).HandlerFunc(httpTraceHdrs(server.ServerInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodCPULoadInfo).HandlerFunc(httpTraceHdrs(server.CPULoadInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodMemUsageInfo).HandlerFunc(httpTraceHdrs(server.MemUsageInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodDrivePerfInfo).HandlerFunc(httpTraceHdrs(server.DrivePerfInfoHandler)).Queries(restQueries(peerRESTDrivePerfSize)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodHardwareCPUInfo).HandlerFunc(httpTraceHdrs(server.CPUInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodHardwareNetworkInfo).HandlerFunc(httpTraceHdrs(server.NetworkInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodDeleteBucket).HandlerFunc(httpTraceHdrs(server.DeleteBucketHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodSignalService).HandlerFunc(httpTraceHdrs(server.SignalServiceHandler)).Queries(restQueries(peerRESTSignal)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodServerUpdate).HandlerFunc(httpTraceHdrs(server.ServerUpdateHandler)).Queries(restQueries(peerRESTUpdateURL, peerRESTSha256Hex, peerRESTLatestRelease)...) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketPolicyRemove).HandlerFunc(httpTraceAll(server.RemoveBucketPolicyHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketPolicySet).HandlerFunc(httpTraceHdrs(server.SetBucketPolicyHandler)).Queries(restQueries(peerRESTBucket)...) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodDeletePolicy).HandlerFunc(httpTraceAll(server.DeletePolicyHandler)).Queries(restQueries(peerRESTPolicy)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLoadPolicy).HandlerFunc(httpTraceAll(server.LoadPolicyHandler)).Queries(restQueries(peerRESTPolicy)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLoadPolicyMapping).HandlerFunc(httpTraceAll(server.LoadPolicyMappingHandler)).Queries(restQueries(peerRESTUserOrGroup)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodDeleteUser).HandlerFunc(httpTraceAll(server.LoadUserHandler)).Queries(restQueries(peerRESTUser)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLoadUser).HandlerFunc(httpTraceAll(server.LoadUserHandler)).Queries(restQueries(peerRESTUser, peerRESTUserTemp)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLoadUsers).HandlerFunc(httpTraceAll(server.LoadUsersHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLoadGroup).HandlerFunc(httpTraceAll(server.LoadGroupHandler)).Queries(restQueries(peerRESTGroup)...) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodStartProfiling).HandlerFunc(httpTraceAll(server.StartProfilingHandler)).Queries(restQueries(peerRESTProfiler)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodDownloadProfilingData).HandlerFunc(httpTraceHdrs(server.DownloadProflingDataHandler)) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodTargetExists).HandlerFunc(httpTraceHdrs(server.TargetExistsHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodSendEvent).HandlerFunc(httpTraceHdrs(server.SendEventHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketNotificationPut).HandlerFunc(httpTraceHdrs(server.PutBucketNotificationHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketNotificationListen).HandlerFunc(httpTraceHdrs(server.ListenBucketNotificationHandler)).Queries(restQueries(peerRESTBucket)...) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodReloadFormat).HandlerFunc(httpTraceHdrs(server.ReloadFormatHandler)).Queries(restQueries(peerRESTDryRun)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketLifecycleSet).HandlerFunc(httpTraceHdrs(server.SetBucketLifecycleHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketLifecycleRemove).HandlerFunc(httpTraceHdrs(server.RemoveBucketLifecycleHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBackgroundOpsStatus).HandlerFunc(server.BackgroundOpsStatusHandler) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodTrace).HandlerFunc(server.TraceHandler) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBackgroundHealStatus).HandlerFunc(server.BackgroundHealStatusHandler) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLog).HandlerFunc(server.ConsoleLogHandler) - - router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(versionMismatchHandler)) + subrouter := router.PathPrefix(peerRESTPrefix).Subrouter() + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodNetReadPerfInfo).HandlerFunc(httpTraceHdrs(server.NetReadPerfInfoHandler)).Queries(restQueries(peerRESTNetPerfSize)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodCollectNetPerfInfo).HandlerFunc(httpTraceHdrs(server.CollectNetPerfInfoHandler)).Queries(restQueries(peerRESTNetPerfSize)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodGetLocks).HandlerFunc(httpTraceHdrs(server.GetLocksHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodServerInfo).HandlerFunc(httpTraceHdrs(server.ServerInfoHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodCPULoadInfo).HandlerFunc(httpTraceHdrs(server.CPULoadInfoHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodMemUsageInfo).HandlerFunc(httpTraceHdrs(server.MemUsageInfoHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDrivePerfInfo).HandlerFunc(httpTraceHdrs(server.DrivePerfInfoHandler)).Queries(restQueries(peerRESTDrivePerfSize)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodHardwareCPUInfo).HandlerFunc(httpTraceHdrs(server.CPUInfoHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodHardwareNetworkInfo).HandlerFunc(httpTraceHdrs(server.NetworkInfoHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDeleteBucket).HandlerFunc(httpTraceHdrs(server.DeleteBucketHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodSignalService).HandlerFunc(httpTraceHdrs(server.SignalServiceHandler)).Queries(restQueries(peerRESTSignal)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodServerUpdate).HandlerFunc(httpTraceHdrs(server.ServerUpdateHandler)).Queries(restQueries(peerRESTUpdateURL, peerRESTSha256Hex, peerRESTLatestRelease)...) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketPolicyRemove).HandlerFunc(httpTraceAll(server.RemoveBucketPolicyHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketPolicySet).HandlerFunc(httpTraceHdrs(server.SetBucketPolicyHandler)).Queries(restQueries(peerRESTBucket)...) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDeletePolicy).HandlerFunc(httpTraceAll(server.DeletePolicyHandler)).Queries(restQueries(peerRESTPolicy)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLoadPolicy).HandlerFunc(httpTraceAll(server.LoadPolicyHandler)).Queries(restQueries(peerRESTPolicy)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLoadPolicyMapping).HandlerFunc(httpTraceAll(server.LoadPolicyMappingHandler)).Queries(restQueries(peerRESTUserOrGroup)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDeleteUser).HandlerFunc(httpTraceAll(server.LoadUserHandler)).Queries(restQueries(peerRESTUser)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLoadUser).HandlerFunc(httpTraceAll(server.LoadUserHandler)).Queries(restQueries(peerRESTUser, peerRESTUserTemp)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLoadUsers).HandlerFunc(httpTraceAll(server.LoadUsersHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLoadGroup).HandlerFunc(httpTraceAll(server.LoadGroupHandler)).Queries(restQueries(peerRESTGroup)...) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodStartProfiling).HandlerFunc(httpTraceAll(server.StartProfilingHandler)).Queries(restQueries(peerRESTProfiler)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDownloadProfilingData).HandlerFunc(httpTraceHdrs(server.DownloadProflingDataHandler)) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodTargetExists).HandlerFunc(httpTraceHdrs(server.TargetExistsHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodSendEvent).HandlerFunc(httpTraceHdrs(server.SendEventHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketNotificationPut).HandlerFunc(httpTraceHdrs(server.PutBucketNotificationHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketNotificationListen).HandlerFunc(httpTraceHdrs(server.ListenBucketNotificationHandler)).Queries(restQueries(peerRESTBucket)...) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodReloadFormat).HandlerFunc(httpTraceHdrs(server.ReloadFormatHandler)).Queries(restQueries(peerRESTDryRun)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketLifecycleSet).HandlerFunc(httpTraceHdrs(server.SetBucketLifecycleHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketLifecycleRemove).HandlerFunc(httpTraceHdrs(server.RemoveBucketLifecycleHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBackgroundOpsStatus).HandlerFunc(server.BackgroundOpsStatusHandler) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodTrace).HandlerFunc(server.TraceHandler) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBackgroundHealStatus).HandlerFunc(server.BackgroundHealStatusHandler) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLog).HandlerFunc(server.ConsoleLogHandler) + + // If none of the routes match add default error handler routes + router.NotFoundHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) + router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) } diff --git a/cmd/posix_test.go b/cmd/posix_test.go index 745ac89f6..b54077d6e 100644 --- a/cmd/posix_test.go +++ b/cmd/posix_test.go @@ -1887,7 +1887,7 @@ func TestPosixVerifyFile(t *testing.T) { // 4) Streaming bitrot check on corrupted file filePath := pathJoin(posixStorage.String(), volName, fileName) - f, err := os.OpenFile(filePath, os.O_WRONLY, 0644) + f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_SYNC, 0644) if err != nil { t.Fatal(err) } diff --git a/cmd/rest/client.go b/cmd/rest/client.go index e6cbccbe2..c58ef9185 100644 --- a/cmd/rest/client.go +++ b/cmd/rest/client.go @@ -54,13 +54,12 @@ type Client struct { // URL query separator constants const ( - resourceSep = "/" - querySep = "?" + querySep = "?" ) // CallWithContext - make a REST call with context. func (c *Client) CallWithContext(ctx context.Context, method string, values url.Values, body io.Reader, length int64) (reply io.ReadCloser, err error) { - req, err := http.NewRequest(http.MethodPost, c.url.String()+resourceSep+method+querySep+values.Encode(), body) + req, err := http.NewRequest(http.MethodPost, c.url.String()+method+querySep+values.Encode(), body) if err != nil { return nil, &NetworkError{err} } diff --git a/cmd/server-main.go b/cmd/server-main.go index 7567470f2..5d9309033 100644 --- a/cmd/server-main.go +++ b/cmd/server-main.go @@ -244,6 +244,9 @@ func serverMain(ctx *cli.Context) { // Handle all server command args. serverHandleCmdArgs(ctx) + // Handle all server environment vars. + serverHandleEnvVars() + // Check and load TLS certificates. var err error globalPublicCerts, globalTLSCerts, globalIsSSL, err = getTLSConfig() @@ -253,9 +256,6 @@ func serverMain(ctx *cli.Context) { globalRootCAs, err = config.GetRootCAs(globalCertsCADir.Get()) logger.FatalIf(err, "Failed to read root CAs (%v)", err) - // Handle all server environment vars. - serverHandleEnvVars() - // Is distributed setup, error out if no certificates are found for HTTPS endpoints. if globalIsDistXL { if globalEndpoints.IsHTTPS() && !globalIsSSL { diff --git a/cmd/storage-rest-client.go b/cmd/storage-rest-client.go index b93621a11..86b5ebcce 100644 --- a/cmd/storage-rest-client.go +++ b/cmd/storage-rest-client.go @@ -460,7 +460,7 @@ func newStorageRESTClient(endpoint Endpoint) (*storageRESTClient, error) { serverURL := &url.URL{ Scheme: scheme, Host: endpoint.Host, - Path: path.Join(storageRESTPath, endpoint.Path), + Path: path.Join(storageRESTPrefix, endpoint.Path, storageRESTVersion), } var tlsConfig *tls.Config diff --git a/cmd/storage-rest-common.go b/cmd/storage-rest-common.go index 81a6da7a6..9df169570 100644 --- a/cmd/storage-rest-common.go +++ b/cmd/storage-rest-common.go @@ -17,30 +17,31 @@ package cmd const ( - storageRESTVersion = "v10" - storageRESTPath = minioReservedBucketPath + "/storage/" + storageRESTVersion + SlashSeparator + storageRESTVersion = "v10" + storageRESTVersionPrefix = SlashSeparator + "v10" + storageRESTPrefix = minioReservedBucketPath + "/storage" ) const ( - storageRESTMethodDiskInfo = "diskinfo" - storageRESTMethodMakeVol = "makevol" - storageRESTMethodStatVol = "statvol" - storageRESTMethodDeleteVol = "deletevol" - storageRESTMethodListVols = "listvols" + storageRESTMethodDiskInfo = "/diskinfo" + storageRESTMethodMakeVol = "/makevol" + storageRESTMethodStatVol = "/statvol" + storageRESTMethodDeleteVol = "/deletevol" + storageRESTMethodListVols = "/listvols" - storageRESTMethodAppendFile = "appendfile" - storageRESTMethodCreateFile = "createfile" - storageRESTMethodWriteAll = "writeall" - storageRESTMethodStatFile = "statfile" - storageRESTMethodReadAll = "readall" - storageRESTMethodReadFile = "readfile" - storageRESTMethodReadFileStream = "readfilestream" - storageRESTMethodListDir = "listdir" - storageRESTMethodWalk = "walk" - storageRESTMethodDeleteFile = "deletefile" - storageRESTMethodDeleteFileBulk = "deletefilebulk" - storageRESTMethodRenameFile = "renamefile" - storageRESTMethodVerifyFile = "verifyfile" + storageRESTMethodAppendFile = "/appendfile" + storageRESTMethodCreateFile = "/createfile" + storageRESTMethodWriteAll = "/writeall" + storageRESTMethodStatFile = "/statfile" + storageRESTMethodReadAll = "/readall" + storageRESTMethodReadFile = "/readfile" + storageRESTMethodReadFileStream = "/readfilestream" + storageRESTMethodListDir = "/listdir" + storageRESTMethodWalk = "/walk" + storageRESTMethodDeleteFile = "/deletefile" + storageRESTMethodDeleteFileBulk = "/deletefilebulk" + storageRESTMethodRenameFile = "/renamefile" + storageRESTMethodVerifyFile = "/verifyfile" ) const ( diff --git a/cmd/storage-rest-server.go b/cmd/storage-rest-server.go index f9cc6151d..2b63acc19 100644 --- a/cmd/storage-rest-server.go +++ b/cmd/storage-rest-server.go @@ -573,43 +573,45 @@ func registerStorageRESTHandlers(router *mux.Router, endpoints EndpointList) { server := &storageRESTServer{storage: storage} - subrouter := router.PathPrefix(path.Join(storageRESTPath, endpoint.Path)).Subrouter() + subrouter := router.PathPrefix(path.Join(storageRESTPrefix, endpoint.Path)).Subrouter() - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodDiskInfo).HandlerFunc(httpTraceHdrs(server.DiskInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodMakeVol).HandlerFunc(httpTraceHdrs(server.MakeVolHandler)).Queries(restQueries(storageRESTVolume)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodStatVol).HandlerFunc(httpTraceHdrs(server.StatVolHandler)).Queries(restQueries(storageRESTVolume)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodDeleteVol).HandlerFunc(httpTraceHdrs(server.DeleteVolHandler)).Queries(restQueries(storageRESTVolume)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodListVols).HandlerFunc(httpTraceHdrs(server.ListVolsHandler)) + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDiskInfo).HandlerFunc(httpTraceHdrs(server.DiskInfoHandler)) + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodMakeVol).HandlerFunc(httpTraceHdrs(server.MakeVolHandler)).Queries(restQueries(storageRESTVolume)...) + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodStatVol).HandlerFunc(httpTraceHdrs(server.StatVolHandler)).Queries(restQueries(storageRESTVolume)...) + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDeleteVol).HandlerFunc(httpTraceHdrs(server.DeleteVolHandler)).Queries(restQueries(storageRESTVolume)...) + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodListVols).HandlerFunc(httpTraceHdrs(server.ListVolsHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodAppendFile).HandlerFunc(httpTraceHdrs(server.AppendFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodAppendFile).HandlerFunc(httpTraceHdrs(server.AppendFileHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodWriteAll).HandlerFunc(httpTraceHdrs(server.WriteAllHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodWriteAll).HandlerFunc(httpTraceHdrs(server.WriteAllHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodCreateFile).HandlerFunc(httpTraceHdrs(server.CreateFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodCreateFile).HandlerFunc(httpTraceHdrs(server.CreateFileHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath, storageRESTLength)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodStatFile).HandlerFunc(httpTraceHdrs(server.StatFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodStatFile).HandlerFunc(httpTraceHdrs(server.StatFileHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodReadAll).HandlerFunc(httpTraceHdrs(server.ReadAllHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadAll).HandlerFunc(httpTraceHdrs(server.ReadAllHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodReadFile).HandlerFunc(httpTraceHdrs(server.ReadFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadFile).HandlerFunc(httpTraceHdrs(server.ReadFileHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath, storageRESTOffset, storageRESTLength, storageRESTBitrotAlgo, storageRESTBitrotHash)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodReadFileStream).HandlerFunc(httpTraceHdrs(server.ReadFileStreamHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadFileStream).HandlerFunc(httpTraceHdrs(server.ReadFileStreamHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath, storageRESTOffset, storageRESTLength)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodListDir).HandlerFunc(httpTraceHdrs(server.ListDirHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodListDir).HandlerFunc(httpTraceHdrs(server.ListDirHandler)). Queries(restQueries(storageRESTVolume, storageRESTDirPath, storageRESTCount, storageRESTLeafFile)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodWalk).HandlerFunc(httpTraceHdrs(server.WalkHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodWalk).HandlerFunc(httpTraceHdrs(server.WalkHandler)). Queries(restQueries(storageRESTVolume, storageRESTDirPath, storageRESTMarkerPath, storageRESTRecursive, storageRESTLeafFile)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodDeleteFile).HandlerFunc(httpTraceHdrs(server.DeleteFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDeleteFile).HandlerFunc(httpTraceHdrs(server.DeleteFileHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodDeleteFileBulk).HandlerFunc(httpTraceHdrs(server.DeleteFileBulkHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDeleteFileBulk).HandlerFunc(httpTraceHdrs(server.DeleteFileBulkHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodRenameFile).HandlerFunc(httpTraceHdrs(server.RenameFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodRenameFile).HandlerFunc(httpTraceHdrs(server.RenameFileHandler)). Queries(restQueries(storageRESTSrcVolume, storageRESTSrcPath, storageRESTDstVolume, storageRESTDstPath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodVerifyFile).HandlerFunc(httpTraceHdrs(server.VerifyFile)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodVerifyFile).HandlerFunc(httpTraceHdrs(server.VerifyFile)). Queries(restQueries(storageRESTVolume, storageRESTFilePath, storageRESTBitrotAlgo, storageRESTBitrotHash, storageRESTLength, storageRESTShardSize)...) } - router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(versionMismatchHandler)) + // If none of the routes match add default error handler routes + router.NotFoundHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) + router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) } diff --git a/cmd/xl-v1-healing-common_test.go b/cmd/xl-v1-healing-common_test.go index fa3e51c07..b55f6a7a8 100644 --- a/cmd/xl-v1-healing-common_test.go +++ b/cmd/xl-v1-healing-common_test.go @@ -216,7 +216,7 @@ func TestListOnlineDisks(t *testing.T) { // appears in outDatedDisks. tamperedIndex = index filePath := pathJoin(xlDisks[index].String(), bucket, object, "part.1") - f, err := os.OpenFile(filePath, os.O_WRONLY, 0) + f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_SYNC, 0) if err != nil { t.Fatalf("Failed to open %s: %s\n", filePath, err) } @@ -319,7 +319,7 @@ func TestDisksWithAllParts(t *testing.T) { for _, info := range partsMetadata[diskIndex].Erasure.Checksums { if info.Name == partName { filePath := pathJoin(xlDisks[diskIndex].String(), bucket, object, partName) - f, err := os.OpenFile(filePath, os.O_WRONLY, 0) + f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_SYNC, 0) if err != nil { t.Fatalf("Failed to open %s: %s\n", filePath, err) }